summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-07 00:11:11 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-07 00:11:11 +0000
commitd4f8f25db649b973f1ae344cb0f8a407862d106b (patch)
treef71f2d2243dc768a1ec44e79556d8020bff51dc7 /spec
parent5f0e3773e9695fd0c9e92ea9180c8a1f5cfaa5c5 (diff)
downloadgitlab-ce-d4f8f25db649b973f1ae344cb0f8a407862d106b.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb66
-rw-r--r--spec/features/commits/user_view_commits_spec.rb22
-rw-r--r--spec/finders/releases_finder_spec.rb11
-rw-r--r--spec/frontend/pipelines/components/pipelines_filtered_search_spec.js74
-rw-r--r--spec/frontend/pipelines/mock_data.js59
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js28
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js63
-rw-r--r--spec/graphql/resolvers/release_resolver_spec.rb51
-rw-r--r--spec/graphql/resolvers/releases_resolver_spec.rb42
-rw-r--r--spec/graphql/types/project_type_spec.rb16
-rw-r--r--spec/graphql/types/release_type_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb270
-rw-r--r--spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb34
13 files changed, 766 insertions, 7 deletions
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 8dc337e3a3d..3c34d41504d 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -145,11 +145,61 @@ describe Projects::PipelinesController do
end
end
- def get_pipelines_index_json
+ context 'filter by scope' do
+ it 'returns matched pipelines' do
+ get_pipelines_index_json(scope: 'running')
+
+ check_pipeline_response(returned: 2, all: 6, running: 2, pending: 1, finished: 3)
+ end
+
+ context 'scope is branches or tags' do
+ before do
+ create(:ci_pipeline, :failed, project: project, ref: 'v1.0.0', tag: true)
+ end
+
+ context 'when scope is branches' do
+ it 'returns matched pipelines' do
+ get_pipelines_index_json(scope: 'branches')
+
+ check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4)
+ end
+ end
+
+ context 'when scope is tags' do
+ it 'returns matched pipelines' do
+ get_pipelines_index_json(scope: 'tags')
+
+ check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4)
+ end
+ end
+ end
+ end
+
+ context 'filter by username' do
+ let!(:pipeline) { create(:ci_pipeline, :running, project: project, user: user) }
+
+ context 'when username exists' do
+ it 'returns matched pipelines' do
+ get_pipelines_index_json(username: user.username)
+
+ check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0)
+ end
+ end
+
+ context 'when username does not exist' do
+ it 'returns empty' do
+ get_pipelines_index_json(username: 'invalid-username')
+
+ check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0)
+ end
+ end
+ end
+
+ def get_pipelines_index_json(params = {})
get :index, params: {
namespace_id: project.namespace,
project_id: project
- },
+ }.merge(params),
format: :json
end
@@ -199,6 +249,18 @@ describe Projects::PipelinesController do
user: user
)
end
+
+ def check_pipeline_response(returned:, all:, running:, pending:, finished:)
+ aggregate_failures do
+ expect(response).to match_response_schema('pipeline')
+
+ expect(json_response['pipelines'].count).to eq returned
+ expect(json_response['count']['all'].to_i).to eq all
+ expect(json_response['count']['running'].to_i).to eq running
+ expect(json_response['count']['pending'].to_i).to eq pending
+ expect(json_response['count']['finished'].to_i).to eq finished
+ end
+ end
end
describe 'GET show.json' do
diff --git a/spec/features/commits/user_view_commits_spec.rb b/spec/features/commits/user_view_commits_spec.rb
new file mode 100644
index 00000000000..133baca8b1c
--- /dev/null
+++ b/spec/features/commits/user_view_commits_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Commit > User view commits' do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:user) { project.creator }
+
+ before do
+ visit project_commits_path(project)
+ end
+
+ describe 'Commits List' do
+ it 'displays the correct number of commits per day in the header' do
+ expect(first('.js-commit-header').find('.commits-count').text).to eq('1 commit')
+ end
+
+ it 'lists the correct number of commits' do
+ expect(page).to have_selector('#commits-list > li:nth-child(2) > ul', count: 1)
+ end
+ end
+end
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
index 3da5ee47b6b..cb4e5fed816 100644
--- a/spec/finders/releases_finder_spec.rb
+++ b/spec/finders/releases_finder_spec.rb
@@ -5,10 +5,11 @@ require 'spec_helper'
describe ReleasesFinder do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
+ let(:params) { {} }
let(:repository) { project.repository }
let(:v1_0_0) { create(:release, project: project, tag: 'v1.0.0') }
let(:v1_1_0) { create(:release, project: project, tag: 'v1.1.0') }
- let(:finder) { described_class.new(project, user) }
+ let(:finder) { described_class.new(project, user, params) }
before do
v1_0_0.update_attribute(:released_at, 2.days.ago)
@@ -64,6 +65,14 @@ describe ReleasesFinder do
expect(subject).to eq([v1_1_0])
end
end
+
+ context 'when a tag parameter is passed' do
+ let(:params) { { tag: 'v1.0.0' } }
+
+ it 'only returns the release with the matching tag' do
+ expect(subject).to eq([v1_0_0])
+ end
+ end
end
end
end
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
new file mode 100644
index 00000000000..ea98a20f3d0
--- /dev/null
+++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
@@ -0,0 +1,74 @@
+import Api from '~/api';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import PipelinesFilteredSearch from '~/pipelines/components/pipelines_filtered_search.vue';
+import { users, mockSearch, pipelineWithStages } from '../mock_data';
+import { GlFilteredSearch } from '@gitlab/ui';
+
+describe('Pipelines filtered search', () => {
+ let wrapper;
+ let mock;
+
+ const findFilteredSearch = () => wrapper.find(GlFilteredSearch);
+ const getSearchToken = type =>
+ findFilteredSearch()
+ .props('availableTokens')
+ .find(token => token.type === type);
+
+ const createComponent = () => {
+ wrapper = mount(PipelinesFilteredSearch, {
+ propsData: {
+ pipelines: [pipelineWithStages],
+ projectId: '21',
+ },
+ attachToDocument: true,
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('displays UI elements', () => {
+ expect(wrapper.isVueInstance()).toBe(true);
+ expect(wrapper.isEmpty()).toBe(false);
+
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
+ it('displays search tokens', () => {
+ expect(getSearchToken('username')).toMatchObject({
+ type: 'username',
+ icon: 'user',
+ title: 'Trigger author',
+ dataType: 'username',
+ unique: true,
+ triggerAuthors: users,
+ operators: [expect.objectContaining({ value: '=' })],
+ });
+ });
+
+ it('fetches and sets project users', () => {
+ expect(Api.projectUsers).toHaveBeenCalled();
+
+ expect(wrapper.vm.projectUsers).toEqual(users);
+ });
+
+ it('emits filterPipelines on submit with correct filter', () => {
+ findFilteredSearch().vm.$emit('submit', mockSearch);
+
+ expect(wrapper.emitted('filterPipelines')).toBeTruthy();
+ expect(wrapper.emitted('filterPipelines')[0]).toEqual([mockSearch]);
+ });
+});
diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js
index f876987cd88..81503192350 100644
--- a/spec/frontend/pipelines/mock_data.js
+++ b/spec/frontend/pipelines/mock_data.js
@@ -421,3 +421,62 @@ export const stageReply = {
path: '/twitter/flight/pipelines/13#deploy',
dropdown_path: '/twitter/flight/pipelines/13/stage.json?stage=deploy',
};
+
+export const users = [
+ {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/root',
+ },
+ {
+ id: 10,
+ name: 'Angel Spinka',
+ username: 'shalonda',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/709df1b65ad06764ee2b0edf1b49fc27?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/shalonda',
+ },
+ {
+ id: 11,
+ name: 'Art Davis',
+ username: 'deja.green',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/bb56834c061522760e7a6dd7d431a306?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/deja.green',
+ },
+ {
+ id: 32,
+ name: 'Arnold Mante',
+ username: 'reported_user_10',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/ab558033a82466d7905179e837d7723a?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/reported_user_10',
+ },
+ {
+ id: 38,
+ name: 'Cher Wintheiser',
+ username: 'reported_user_16',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/2640356e8b5bc4314133090994ed162b?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/reported_user_16',
+ },
+ {
+ id: 39,
+ name: 'Bethel Wolf',
+ username: 'reported_user_17',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/4b948694fadba4b01e4acfc06b065e8e?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/reported_user_17',
+ },
+];
+
+export const mockSearch = { type: 'username', value: { data: 'root', operator: '=' } };
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index 40cd0ad9047..40c493e3aa5 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -1,10 +1,12 @@
+import Api from '~/api';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import waitForPromises from 'helpers/wait_for_promises';
import PipelinesComponent from '~/pipelines/components/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store';
-import { pipelineWithStages, stageReply } from './mock_data';
+import { pipelineWithStages, stageReply, users, mockSearch } from './mock_data';
+import { GlFilteredSearch } from '@gitlab/ui';
describe('Pipelines', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
@@ -42,10 +44,14 @@ describe('Pipelines', () => {
...paths,
};
+ const findFilteredSearch = () => wrapper.find(GlFilteredSearch);
+
const createComponent = (props = defaultProps, methods) => {
wrapper = mount(PipelinesComponent, {
+ provide: { glFeatures: { filterPipelinesSearch: true } },
propsData: {
store: new Store(),
+ projectId: '21',
...props,
},
methods: {
@@ -57,6 +63,7 @@ describe('Pipelines', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
pipelines = getJSONFixture(jsonFixtureName);
+ jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
});
afterEach(() => {
@@ -656,4 +663,23 @@ describe('Pipelines', () => {
});
});
});
+
+ describe('Pipeline filters', () => {
+ beforeEach(() => {
+ mock.onGet(paths.endpoint).reply(200, pipelines);
+ createComponent();
+
+ return waitForPromises();
+ });
+
+ it('updates request data and query params on filter submit', () => {
+ const updateContentMock = jest.spyOn(wrapper.vm, 'updateContent');
+ const expectedQueryParams = { page: '1', scope: 'all', username: 'root' };
+
+ findFilteredSearch().vm.$emit('submit', [mockSearch]);
+
+ expect(wrapper.vm.requestData).toEqual(expectedQueryParams);
+ expect(updateContentMock).toHaveBeenCalledWith(expectedQueryParams);
+ });
+ });
});
diff --git a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
new file mode 100644
index 00000000000..56aba62ede2
--- /dev/null
+++ b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
@@ -0,0 +1,63 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import PipelineTriggerAuthorToken from '~/pipelines/components/tokens/pipeline_trigger_author_token.vue';
+import { users } from '../mock_data';
+
+describe('Pipeline Trigger Author Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
+
+ const stubs = {
+ GlFilteredSearchToken: {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ },
+ };
+
+ const defaultProps = {
+ config: {
+ type: 'username',
+ icon: 'user',
+ title: 'Trigger author',
+ dataType: 'username',
+ unique: true,
+ triggerAuthors: users,
+ },
+ };
+
+ const createComponent = (props = {}, options) => {
+ wrapper = shallowMount(PipelineTriggerAuthorToken, {
+ propsData: {
+ ...props,
+ ...defaultProps,
+ },
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent({ value: { data: '' } });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ describe('shows trigger authors correctly', () => {
+ it('renders all trigger authors', () => {
+ createComponent({ value: { data: '' } }, { stubs });
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(7);
+ });
+
+ it('renders only the trigger author searched for', () => {
+ createComponent({ value: { data: 'root' } }, { stubs });
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(2);
+ });
+ });
+});
diff --git a/spec/graphql/resolvers/release_resolver_spec.rb b/spec/graphql/resolvers/release_resolver_spec.rb
new file mode 100644
index 00000000000..71aa4bbb439
--- /dev/null
+++ b/spec/graphql/resolvers/release_resolver_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::ReleaseResolver do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:release) { create(:release, project: project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:public_user) { create(:user) }
+
+ let(:args) { { tag_name: release.tag } }
+
+ before do
+ project.add_developer(developer)
+ end
+
+ describe '#resolve' do
+ context 'when the user does not have access to the project' do
+ let(:current_user) { public_user }
+
+ it 'returns nil' do
+ expect(resolve_release).to be_nil
+ end
+ end
+
+ context "when the user has full access to the project's releases" do
+ let(:current_user) { developer }
+
+ it 'returns the release associated with the specified tag' do
+ expect(resolve_release).to eq(release)
+ end
+
+ context 'when no tag_name argument was passed' do
+ let(:args) { {} }
+
+ it 'raises an error' do
+ expect { resolve_release }.to raise_error(ArgumentError, "missing keyword: tag_name")
+ end
+ end
+ end
+ end
+
+ private
+
+ def resolve_release
+ context = { current_user: current_user }
+ resolve(described_class, obj: project, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/releases_resolver_spec.rb b/spec/graphql/resolvers/releases_resolver_spec.rb
new file mode 100644
index 00000000000..9de539b417a
--- /dev/null
+++ b/spec/graphql/resolvers/releases_resolver_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::ReleasesResolver do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:release_v1) { create(:release, project: project, tag: 'v1.0.0') }
+ let_it_be(:release_v2) { create(:release, project: project, tag: 'v2.0.0') }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:public_user) { create(:user) }
+
+ before do
+ project.add_developer(developer)
+ end
+
+ describe '#resolve' do
+ context 'when the user does not have access to the project' do
+ let(:current_user) { public_user }
+
+ it 'returns an empty array' do
+ expect(resolve_releases).to eq([])
+ end
+ end
+
+ context "when the user has full access to the project's releases" do
+ let(:current_user) { developer }
+
+ it 'returns all releases associated to the project' do
+ expect(resolve_releases).to eq([release_v1, release_v2])
+ end
+ end
+ end
+
+ private
+
+ def resolve_releases
+ context = { current_user: current_user }
+ resolve(described_class, obj: project, args: {}, ctx: context)
+ end
+end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 6ea852190c9..e05c5d5e6ad 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -24,7 +24,7 @@ describe GitlabSchema.types['Project'] do
namespace group statistics repository merge_requests merge_request issues
issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets
grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments
- boards jira_import_status jira_imports services
+ boards jira_import_status jira_imports services releases release
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -96,4 +96,18 @@ describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::Projects::ServiceType.connection_type) }
end
+
+ describe 'releases field' do
+ subject { described_class.fields['release'] }
+
+ it { is_expected.to have_graphql_type(Types::ReleaseType) }
+ it { is_expected.to have_graphql_resolver(Resolvers::ReleaseResolver) }
+ end
+
+ describe 'release field' do
+ subject { described_class.fields['releases'] }
+
+ it { is_expected.to have_graphql_type(Types::ReleaseType.connection_type) }
+ it { is_expected.to have_graphql_resolver(Resolvers::ReleasesResolver) }
+ end
end
diff --git a/spec/graphql/types/release_type_spec.rb b/spec/graphql/types/release_type_spec.rb
new file mode 100644
index 00000000000..e68b8cd549d
--- /dev/null
+++ b/spec/graphql/types/release_type_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['Release'] do
+ it { expect(described_class).to require_graphql_authorizations(:read_release) }
+
+ it 'has the expected fields' do
+ expected_fields = %w[
+ tag_name tag_path
+ description description_html
+ name evidence_sha milestones author commit
+ created_at released_at
+ ]
+
+ expect(described_class).to include_graphql_fields(*expected_fields)
+ end
+
+ describe 'milestones field' do
+ subject { described_class.fields['milestones'] }
+
+ it { is_expected.to have_graphql_type(Types::MilestoneType.connection_type) }
+ end
+
+ describe 'author field' do
+ subject { described_class.fields['author'] }
+
+ it { is_expected.to have_graphql_type(Types::UserType) }
+ end
+
+ describe 'commit field' do
+ subject { described_class.fields['commit'] }
+
+ it { is_expected.to have_graphql_type(Types::CommitType) }
+ it { is_expected.to require_graphql_authorizations(:reporter_access) }
+ end
+end
diff --git a/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
new file mode 100644
index 00000000000..31a330f46b1
--- /dev/null
+++ b/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
@@ -0,0 +1,270 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Ci::Reports::AccessibilityReportsComparer do
+ let(:comparer) { described_class.new(base_reports, head_reports) }
+ let(:base_reports) { Gitlab::Ci::Reports::AccessibilityReports.new }
+ let(:head_reports) { Gitlab::Ci::Reports::AccessibilityReports.new }
+ let(:url) { "https://gitlab.com" }
+ let(:single_error) do
+ [
+ {
+ "code" => "WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.A.NoContent",
+ "type" => "error",
+ "typeCode" => 1,
+ "message" => "Anchor element found with a valid href attribute, but no link content has been supplied.",
+ "context" => %{<a href="/" class="navbar-brand animated"><svg height="36" viewBox="0 0 1...</a>},
+ "selector" => "#main-nav > div:nth-child(1) > a",
+ "runner" => "htmlcs",
+ "runnerExtras" => {}
+ }
+ ]
+ end
+ let(:different_error) do
+ [
+ {
+ "code" => "WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail",
+ "type" => "error",
+ "typeCode" => 1,
+ "message" => "This element has insufficient contrast at this conformance level.",
+ "context" => %{<a href="/stages-devops-lifecycle/" class="main-nav-link">Product</a>},
+ "selector" => "#main-nav > div:nth-child(2) > ul > li:nth-child(1) > a",
+ "runner" => "htmlcs",
+ "runnerExtras" => {}
+ }
+ ]
+ end
+
+ describe '#status' do
+ subject { comparer.status }
+
+ context 'when head report has an error' do
+ before do
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns status failed' do
+ expect(subject).to eq(described_class::STATUS_FAILED)
+ end
+ end
+
+ context 'when head reports does not have errors' do
+ before do
+ head_reports.add_url(url, [])
+ end
+
+ it 'returns status success' do
+ expect(subject).to eq(described_class::STATUS_SUCCESS)
+ end
+ end
+ end
+
+ describe '#errors_count' do
+ subject { comparer.errors_count }
+
+ context 'when head report has an error' do
+ before do
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns the number of new errors' do
+ expect(subject).to eq(1)
+ end
+ end
+
+ context 'when head reports does not have an error' do
+ before do
+ head_reports.add_url(url, [])
+ end
+
+ it 'returns the number new errors' do
+ expect(subject).to eq(0)
+ end
+ end
+ end
+
+ describe '#resolved_count' do
+ subject { comparer.resolved_count }
+
+ context 'when base reports has an error and head has a different error' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, different_error)
+ end
+
+ it 'returns the resolved count' do
+ expect(subject).to eq(1)
+ end
+ end
+
+ context 'when base reports has errors head has no errors' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, [])
+ end
+
+ it 'returns the resolved count' do
+ expect(subject).to eq(1)
+ end
+ end
+
+ context 'when base reports has errors and head has the same error' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns zero' do
+ expect(subject).to eq(0)
+ end
+ end
+
+ context 'when base reports does not have errors and head has errors' do
+ before do
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns the number of resolved errors' do
+ expect(subject).to eq(0)
+ end
+ end
+ end
+
+ describe '#total_count' do
+ subject { comparer.total_count }
+
+ context 'when base reports has an error' do
+ before do
+ base_reports.add_url(url, single_error)
+ end
+
+ it 'returns the error count' do
+ expect(subject).to eq(1)
+ end
+ end
+
+ context 'when head report has an error' do
+ before do
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns the error count' do
+ expect(subject).to eq(1)
+ end
+ end
+
+ context 'when base report has errors and head report has errors' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, different_error)
+ end
+
+ it 'returns the error count' do
+ expect(subject).to eq(2)
+ end
+ end
+ end
+
+ describe '#existing_errors' do
+ subject { comparer.existing_errors }
+
+ context 'when base report has errors and head has a different error' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, different_error)
+ end
+
+ it 'returns the existing errors' do
+ expect(subject.size).to eq(1)
+ expect(subject.first["code"]).to eq("WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.A.NoContent")
+ end
+ end
+
+ context 'when base report does not have errors and head has errors' do
+ before do
+ base_reports.add_url(url, [])
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns an empty array' do
+ expect(subject).to be_empty
+ end
+ end
+ end
+
+ describe '#new_errors' do
+ subject { comparer.new_errors }
+
+ context 'when base reports has errors and head has more errors' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, single_error + different_error)
+ end
+
+ it 'returns new errors between base and head reports' do
+ expect(subject.size).to eq(1)
+ expect(subject.first["code"]).to eq("WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail")
+ end
+ end
+
+ context 'when base reports has an error and head has no errors' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, [])
+ end
+
+ it 'returns an empty array' do
+ expect(subject).to be_empty
+ end
+ end
+
+ context 'when base reports does not have errors and head has errors' do
+ before do
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns the new error' do
+ expect(subject.size).to eq(1)
+ expect(subject.first["code"]).to eq("WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.A.NoContent")
+ end
+ end
+ end
+
+ describe '#resolved_errors' do
+ subject { comparer.resolved_errors }
+
+ context 'when base report has errors and head has more errors' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, single_error + different_error)
+ end
+
+ it 'returns an empty array' do
+ expect(subject).to be_empty
+ end
+ end
+
+ context 'when base reports has errors and head has a different error' do
+ before do
+ base_reports.add_url(url, single_error)
+ head_reports.add_url(url, different_error)
+ end
+
+ it 'returns the resolved errors' do
+ expect(subject.size).to eq(1)
+ expect(subject.first["code"]).to eq("WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.A.NoContent")
+ end
+ end
+
+ context 'when base reports does not have errors and head has errors' do
+ before do
+ head_reports.add_url(url, single_error)
+ end
+
+ it 'returns an empty array' do
+ expect(subject).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb b/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
index e7771ed15a4..0dc13b464b1 100644
--- a/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
@@ -12,7 +12,7 @@ describe Gitlab::Ci::Reports::AccessibilityReports do
"type": "error",
"typeCode": 1,
"message": "Anchor element found with a valid href attribute, but no link content has been supplied.",
- "context": "<a href=\"/customers/worldline\">\n<svg viewBox=\"0 0 509 89\" xmln...</a>",
+ "context": %{<a href="/customers/worldline"><svg viewBox="0 0 509 89" xmln...</a>},
"selector": "html > body > div:nth-child(9) > div:nth-child(2) > a:nth-child(17)",
"runner": "htmlcs",
"runnerExtras": {}
@@ -22,7 +22,7 @@ describe Gitlab::Ci::Reports::AccessibilityReports do
"type": "error",
"typeCode": 1,
"message": "Anchor element found with a valid href attribute, but no link content has been supplied.",
- "context": "<a href=\"/customers/equinix\">\n<svg xmlns=\"http://www.w3.org/...</a>",
+ "context": %{<a href="/customers/equinix"><svg xmlns="http://www.w3.org/...</a>},
"selector": "html > body > div:nth-child(9) > div:nth-child(2) > a:nth-child(18)",
"runner": "htmlcs",
"runnerExtras": {}
@@ -199,4 +199,34 @@ describe Gitlab::Ci::Reports::AccessibilityReports do
end
end
end
+
+ describe '#all_errors' do
+ subject { accessibility_report.all_errors }
+
+ context 'when data has errors' do
+ before do
+ accessibility_report.add_url(url, data)
+ end
+
+ it 'returns all errors' do
+ expect(subject.size).to eq(2)
+ end
+ end
+
+ context 'when data has no errors' do
+ before do
+ accessibility_report.add_url(url, [])
+ end
+
+ it 'returns an empty array' do
+ expect(subject).to eq([])
+ end
+ end
+
+ context 'when accessibility report has no data' do
+ it 'returns an empty array' do
+ expect(subject).to eq([])
+ end
+ end
+ end
end