diff options
Diffstat (limited to 'spec/frontend/reports/accessibility_report')
5 files changed, 515 insertions, 0 deletions
diff --git a/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js b/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js new file mode 100644 index 00000000000..a036588596a --- /dev/null +++ b/spec/frontend/reports/accessibility_report/grouped_accessibility_reports_app_spec.js @@ -0,0 +1,126 @@ +import { mount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import GroupedAccessibilityReportsApp from '~/reports/accessibility_report/grouped_accessibility_reports_app.vue'; +import AccessibilityIssueBody from '~/reports/accessibility_report/components/accessibility_issue_body.vue'; +import store from '~/reports/accessibility_report/store'; +import { mockReport } from './mock_data'; + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('Grouped accessibility reports app', () => { + const Component = localVue.extend(GroupedAccessibilityReportsApp); + let wrapper; + let mockStore; + + const mountComponent = () => { + wrapper = mount(Component, { + store: mockStore, + localVue, + propsData: { + endpoint: 'endpoint.json', + }, + methods: { + fetchReport: () => {}, + }, + }); + }; + + const findHeader = () => wrapper.find('[data-testid="report-section-code-text"]'); + + beforeEach(() => { + mockStore = store(); + mountComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('while loading', () => { + beforeEach(() => { + mockStore.state.isLoading = true; + mountComponent(); + }); + + it('renders loading state', () => { + expect(findHeader().text()).toEqual('Accessibility scanning results are being parsed'); + }); + }); + + describe('with error', () => { + beforeEach(() => { + mockStore.state.isLoading = false; + mockStore.state.hasError = true; + mountComponent(); + }); + + it('renders error state', () => { + expect(findHeader().text()).toEqual('Accessibility scanning failed loading results'); + }); + }); + + describe('with a report', () => { + describe('with no issues', () => { + beforeEach(() => { + mockStore.state.report = { + summary: { + errored: 0, + }, + }; + }); + + it('renders no issues header', () => { + expect(findHeader().text()).toContain( + 'Accessibility scanning detected no issues for the source branch only', + ); + }); + }); + + describe('with one issue', () => { + beforeEach(() => { + mockStore.state.report = { + summary: { + errored: 1, + }, + }; + }); + + it('renders one issue header', () => { + expect(findHeader().text()).toContain( + 'Accessibility scanning detected 1 issue for the source branch only', + ); + }); + }); + + describe('with multiple issues', () => { + beforeEach(() => { + mockStore.state.report = { + summary: { + errored: 2, + }, + }; + }); + + it('renders multiple issues header', () => { + expect(findHeader().text()).toContain( + 'Accessibility scanning detected 2 issues for the source branch only', + ); + }); + }); + + describe('with issues to show', () => { + beforeEach(() => { + mockStore.state.report = mockReport; + }); + + it('renders custom accessibility issue body', () => { + const issueBody = wrapper.find(AccessibilityIssueBody); + + expect(issueBody.props('issue').code).toBe(mockReport.new_errors[0].code); + expect(issueBody.props('issue').message).toBe(mockReport.new_errors[0].message); + expect(issueBody.props('isNew')).toBe(true); + }); + }); + }); +}); diff --git a/spec/frontend/reports/accessibility_report/mock_data.js b/spec/frontend/reports/accessibility_report/mock_data.js new file mode 100644 index 00000000000..f8e832c1ce5 --- /dev/null +++ b/spec/frontend/reports/accessibility_report/mock_data.js @@ -0,0 +1,55 @@ +export const mockReport = { + status: 'failed', + summary: { + total: 2, + resolved: 0, + errored: 2, + }, + new_errors: [ + { + code: 'WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail', + type: 'error', + typeCode: 1, + message: + 'This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.84:1. Recommendation: change text colour to #767676.', + 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: {}, + }, + ], + new_notes: [], + new_warnings: [], + resolved_errors: [ + { + 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: {}, + }, + ], + resolved_notes: [], + resolved_warnings: [], + existing_errors: [ + { + 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: {}, + }, + ], + existing_notes: [], + existing_warnings: [], +}; + +export default () => {}; diff --git a/spec/frontend/reports/accessibility_report/store/actions_spec.js b/spec/frontend/reports/accessibility_report/store/actions_spec.js new file mode 100644 index 00000000000..129a5bade86 --- /dev/null +++ b/spec/frontend/reports/accessibility_report/store/actions_spec.js @@ -0,0 +1,121 @@ +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; +import * as actions from '~/reports/accessibility_report/store/actions'; +import * as types from '~/reports/accessibility_report/store/mutation_types'; +import createStore from '~/reports/accessibility_report/store'; +import { TEST_HOST } from 'spec/test_constants'; +import testAction from 'helpers/vuex_action_helper'; +import { mockReport } from '../mock_data'; + +describe('Accessibility Reports actions', () => { + let localState; + let localStore; + + beforeEach(() => { + localStore = createStore(); + localState = localStore.state; + }); + + describe('setEndpoints', () => { + it('should commit SET_ENDPOINTS mutation', done => { + const endpoint = 'endpoint.json'; + + testAction( + actions.setEndpoint, + endpoint, + localState, + [{ type: types.SET_ENDPOINT, payload: endpoint }], + [], + done, + ); + }); + }); + + describe('fetchReport', () => { + let mock; + + beforeEach(() => { + localState.endpoint = `${TEST_HOST}/endpoint.json`; + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + actions.stopPolling(); + actions.clearEtagPoll(); + }); + + describe('success', () => { + it('should commit REQUEST_REPORT mutation and dispatch receiveReportSuccess', done => { + const data = { report: { summary: {} } }; + mock.onGet(`${TEST_HOST}/endpoint.json`).reply(200, data); + + testAction( + actions.fetchReport, + null, + localState, + [{ type: types.REQUEST_REPORT }], + [ + { + payload: { status: 200, data }, + type: 'receiveReportSuccess', + }, + ], + done, + ); + }); + }); + + describe('error', () => { + it('should commit REQUEST_REPORT and RECEIVE_REPORT_ERROR mutations', done => { + mock.onGet(`${TEST_HOST}/endpoint.json`).reply(500); + + testAction( + actions.fetchReport, + null, + localState, + [{ type: types.REQUEST_REPORT }], + [{ type: 'receiveReportError' }], + done, + ); + }); + }); + }); + + describe('receiveReportSuccess', () => { + it('should commit RECEIVE_REPORT_SUCCESS mutation with 200', done => { + testAction( + actions.receiveReportSuccess, + { status: 200, data: mockReport }, + localState, + [{ type: types.RECEIVE_REPORT_SUCCESS, payload: mockReport }], + [{ type: 'stopPolling' }], + done, + ); + }); + + it('should not commit RECEIVE_REPORTS_SUCCESS mutation with 204', done => { + testAction( + actions.receiveReportSuccess, + { status: 204, data: mockReport }, + localState, + [], + [], + done, + ); + }); + }); + + describe('receiveReportError', () => { + it('should commit RECEIVE_REPORT_ERROR mutation', done => { + testAction( + actions.receiveReportError, + null, + localState, + [{ type: types.RECEIVE_REPORT_ERROR }], + [{ type: 'stopPolling' }], + done, + ); + }); + }); +}); diff --git a/spec/frontend/reports/accessibility_report/store/getters_spec.js b/spec/frontend/reports/accessibility_report/store/getters_spec.js new file mode 100644 index 00000000000..d74c71cfa09 --- /dev/null +++ b/spec/frontend/reports/accessibility_report/store/getters_spec.js @@ -0,0 +1,149 @@ +import * as getters from '~/reports/accessibility_report/store/getters'; +import createStore from '~/reports/accessibility_report/store'; +import { LOADING, ERROR, SUCCESS, STATUS_FAILED } from '~/reports/constants'; + +describe('Accessibility reports store getters', () => { + let localState; + let localStore; + + beforeEach(() => { + localStore = createStore(); + localState = localStore.state; + }); + + describe('summaryStatus', () => { + describe('when summary is loading', () => { + it('returns loading status', () => { + localState.isLoading = true; + + expect(getters.summaryStatus(localState)).toEqual(LOADING); + }); + }); + + describe('when summary has error', () => { + it('returns error status', () => { + localState.hasError = true; + + expect(getters.summaryStatus(localState)).toEqual(ERROR); + }); + }); + + describe('when summary has failed status', () => { + it('returns loading status', () => { + localState.status = STATUS_FAILED; + + expect(getters.summaryStatus(localState)).toEqual(ERROR); + }); + }); + + describe('when summary has successfully loaded', () => { + it('returns loading status', () => { + expect(getters.summaryStatus(localState)).toEqual(SUCCESS); + }); + }); + }); + + describe('groupedSummaryText', () => { + describe('when state is loading', () => { + it('returns the loading summary message', () => { + localState.isLoading = true; + const result = 'Accessibility scanning results are being parsed'; + + expect(getters.groupedSummaryText(localState)).toEqual(result); + }); + }); + + describe('when state has error', () => { + it('returns the error summary message', () => { + localState.hasError = true; + const result = 'Accessibility scanning failed loading results'; + + expect(getters.groupedSummaryText(localState)).toEqual(result); + }); + }); + + describe('when state has successfully loaded', () => { + describe('when report has errors', () => { + it('returns summary message containing number of errors', () => { + localState.report = { + summary: { + errored: 2, + }, + }; + const result = 'Accessibility scanning detected 2 issues for the source branch only'; + + expect(getters.groupedSummaryText(localState)).toEqual(result); + }); + }); + + describe('when report has no errors', () => { + it('returns summary message containing no errors', () => { + localState.report = { + summary: { + errored: 0, + }, + }; + const result = 'Accessibility scanning detected no issues for the source branch only'; + + expect(getters.groupedSummaryText(localState)).toEqual(result); + }); + }); + }); + }); + + describe('shouldRenderIssuesList', () => { + describe('when has issues to render', () => { + it('returns true', () => { + localState.report = { + existing_errors: [{ name: 'Issue' }], + }; + + expect(getters.shouldRenderIssuesList(localState)).toEqual(true); + }); + }); + + describe('when does not have issues to render', () => { + it('returns false', () => { + localState.report = { + status: 'success', + summary: { errored: 0 }, + }; + + expect(getters.shouldRenderIssuesList(localState)).toEqual(false); + }); + }); + }); + + describe('unresolvedIssues', () => { + it('returns the array unresolved errors', () => { + localState.report = { + existing_errors: [1], + }; + const result = [1]; + + expect(getters.unresolvedIssues(localState)).toEqual(result); + }); + }); + + describe('resolvedIssues', () => { + it('returns array of resolved errors', () => { + localState.report = { + resolved_errors: [1], + }; + const result = [1]; + + expect(getters.resolvedIssues(localState)).toEqual(result); + }); + }); + + describe('newIssues', () => { + it('returns array of new errors', () => { + localState.report = { + new_errors: [1], + }; + const result = [1]; + + expect(getters.newIssues(localState)).toEqual(result); + }); + }); +}); diff --git a/spec/frontend/reports/accessibility_report/store/mutations_spec.js b/spec/frontend/reports/accessibility_report/store/mutations_spec.js new file mode 100644 index 00000000000..a4e9571b721 --- /dev/null +++ b/spec/frontend/reports/accessibility_report/store/mutations_spec.js @@ -0,0 +1,64 @@ +import mutations from '~/reports/accessibility_report/store/mutations'; +import createStore from '~/reports/accessibility_report/store'; + +describe('Accessibility Reports mutations', () => { + let localState; + let localStore; + + beforeEach(() => { + localStore = createStore(); + localState = localStore.state; + }); + + describe('SET_ENDPOINT', () => { + it('sets endpoint to given value', () => { + const endpoint = 'endpoint.json'; + mutations.SET_ENDPOINT(localState, endpoint); + + expect(localState.endpoint).toEqual(endpoint); + }); + }); + + describe('REQUEST_REPORT', () => { + it('sets isLoading to true', () => { + mutations.REQUEST_REPORT(localState); + + expect(localState.isLoading).toEqual(true); + }); + }); + + describe('RECEIVE_REPORT_SUCCESS', () => { + it('sets isLoading to false', () => { + mutations.RECEIVE_REPORT_SUCCESS(localState, {}); + + expect(localState.isLoading).toEqual(false); + }); + + it('sets hasError to false', () => { + mutations.RECEIVE_REPORT_SUCCESS(localState, {}); + + expect(localState.hasError).toEqual(false); + }); + + it('sets report to response report', () => { + const report = { data: 'testing' }; + mutations.RECEIVE_REPORT_SUCCESS(localState, report); + + expect(localState.report).toEqual(report); + }); + }); + + describe('RECEIVE_REPORT_ERROR', () => { + it('sets isLoading to false', () => { + mutations.RECEIVE_REPORT_ERROR(localState); + + expect(localState.isLoading).toEqual(false); + }); + + it('sets hasError to true', () => { + mutations.RECEIVE_REPORT_ERROR(localState); + + expect(localState.hasError).toEqual(true); + }); + }); +}); |