Commit ddc74809 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch 'a11y-mr-widget-update' into 'master'

Switch to backend a11y comparison

See merge request gitlab-org/gitlab!31487
parents f55c7c11 5412b8aa
...@@ -13,11 +13,7 @@ export default { ...@@ -13,11 +13,7 @@ export default {
IssuesList, IssuesList,
}, },
props: { props: {
baseEndpoint: { endpoint: {
type: String,
required: true,
},
headEndpoint: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -34,15 +30,12 @@ export default { ...@@ -34,15 +30,12 @@ export default {
]), ]),
}, },
created() { created() {
this.setEndpoints({ this.setEndpoint(this.endpoint);
baseEndpoint: this.baseEndpoint,
headEndpoint: this.headEndpoint,
});
this.fetchReport(); this.fetchReport();
}, },
methods: { methods: {
...mapActions(['fetchReport', 'setEndpoints']), ...mapActions(['fetchReport', 'setEndpoint']),
}, },
}; };
</script> </script>
......
import Visibility from 'visibilityjs';
import Poll from '~/lib/utils/poll';
import httpStatusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { parseAccessibilityReport, compareAccessibilityReports } from './utils';
import { s__ } from '~/locale';
export const setEndpoints = ({ commit }, { baseEndpoint, headEndpoint }) => let eTagPoll;
commit(types.SET_ENDPOINTS, { baseEndpoint, headEndpoint });
export const clearEtagPoll = () => {
eTagPoll = null;
};
export const stopPolling = () => {
if (eTagPoll) eTagPoll.stop();
};
export const restartPolling = () => {
if (eTagPoll) eTagPoll.restart();
};
export const setEndpoint = ({ commit }, endpoint) => commit(types.SET_ENDPOINT, endpoint);
/**
* We need to poll the report endpoint while they are being parsed in the Backend.
* This can take up to one minute.
*
* Poll.js will handle etag response.
* While http status code is 204, it means it's parsing, and we'll keep polling
* When http status code is 200, it means parsing is done, we can show the results & stop polling
* When http status code is 500, it means parsing went wrong and we stop polling
*/
export const fetchReport = ({ state, dispatch, commit }) => { export const fetchReport = ({ state, dispatch, commit }) => {
commit(types.REQUEST_REPORT); commit(types.REQUEST_REPORT);
// If we don't have both endpoints, throw an error. eTagPoll = new Poll({
if (!state.baseEndpoint || !state.headEndpoint) { resource: {
commit( getReport(endpoint) {
types.RECEIVE_REPORT_ERROR, return axios.get(endpoint);
s__('AccessibilityReport|Accessibility report artifact not found'), },
); },
return; data: state.endpoint,
method: 'getReport',
successCallback: ({ status, data }) => dispatch('receiveReportSuccess', { status, data }),
errorCallback: () => dispatch('receiveReportError'),
});
if (!Visibility.hidden()) {
eTagPoll.makeRequest();
} else {
axios
.get(state.endpoint)
.then(({ status, data }) => dispatch('receiveReportSuccess', { status, data }))
.catch(() => dispatch('receiveReportError'));
} }
Promise.all([ Visibility.change(() => {
axios.get(state.baseEndpoint).then(response => ({ if (!Visibility.hidden() && state.isLoading) {
...response.data, dispatch('restartPolling');
isHead: false, } else {
})), dispatch('stopPolling');
axios.get(state.headEndpoint).then(response => ({ }
...response.data, });
isHead: true, };
})),
]) export const receiveReportSuccess = ({ commit, dispatch }, { status, data }) => {
.then(responses => dispatch('receiveReportSuccess', responses)) if (status === httpStatusCodes.OK) {
.catch(() => commit(types.RECEIVE_REPORT_SUCCESS, data);
commit( // Stop polling since we have the information already parsed and it won't be changing
types.RECEIVE_REPORT_ERROR, dispatch('stopPolling');
s__('AccessibilityReport|Failed to retrieve accessibility report'), }
),
);
}; };
export const receiveReportSuccess = ({ commit }, responses) => { export const receiveReportError = ({ commit, dispatch }) => {
const parsedReports = responses.map(response => ({ commit(types.RECEIVE_REPORT_ERROR);
isHead: response.isHead, dispatch('stopPolling');
issues: parseAccessibilityReport(response),
}));
const report = compareAccessibilityReports(parsedReports);
commit(types.RECEIVE_REPORT_SUCCESS, report);
}; };
// prevent babel-plugin-rewire from generating an invalid default during karma tests // prevent babel-plugin-rewire from generating an invalid default during karma tests
......
...@@ -10,8 +10,7 @@ export const groupedSummaryText = state => { ...@@ -10,8 +10,7 @@ export const groupedSummaryText = state => {
return s__('Reports|Accessibility scanning failed loading results'); return s__('Reports|Accessibility scanning failed loading results');
} }
const numberOfResults = const numberOfResults = state.report?.summary?.errored || 0;
(state.report?.summary?.errors || 0) + (state.report?.summary?.warnings || 0);
if (numberOfResults === 0) { if (numberOfResults === 0) {
return s__('Reports|Accessibility scanning detected no issues for the source branch only'); return s__('Reports|Accessibility scanning detected no issues for the source branch only');
} }
......
export const SET_ENDPOINTS = 'SET_ENDPOINTS'; export const SET_ENDPOINT = 'SET_ENDPOINT';
export const REQUEST_REPORT = 'REQUEST_REPORT'; export const REQUEST_REPORT = 'REQUEST_REPORT';
export const RECEIVE_REPORT_SUCCESS = 'RECEIVE_REPORT_SUCCESS'; export const RECEIVE_REPORT_SUCCESS = 'RECEIVE_REPORT_SUCCESS';
......
import * as types from './mutation_types'; import * as types from './mutation_types';
export default { export default {
[types.SET_ENDPOINTS](state, { baseEndpoint, headEndpoint }) { [types.SET_ENDPOINT](state, endpoint) {
state.baseEndpoint = baseEndpoint; state.endpoint = endpoint;
state.headEndpoint = headEndpoint;
}, },
[types.REQUEST_REPORT](state) { [types.REQUEST_REPORT](state) {
state.isLoading = true; state.isLoading = true;
...@@ -13,10 +12,9 @@ export default { ...@@ -13,10 +12,9 @@ export default {
state.isLoading = false; state.isLoading = false;
state.report = report; state.report = report;
}, },
[types.RECEIVE_REPORT_ERROR](state, message) { [types.RECEIVE_REPORT_ERROR](state) {
state.isLoading = false; state.isLoading = false;
state.hasError = true; state.hasError = true;
state.errorMessage = message;
state.report = {}; state.report = {};
}, },
}; };
export default (initialState = {}) => ({ export default (initialState = {}) => ({
baseEndpoint: initialState.baseEndpoint || '', endpoint: initialState.endpoint || '',
headEndpoint: initialState.headEndpoint || '',
isLoading: initialState.isLoading || false, isLoading: initialState.isLoading || false,
hasError: initialState.hasError || false, hasError: initialState.hasError || false,
...@@ -11,9 +10,8 @@ export default (initialState = {}) => ({ ...@@ -11,9 +10,8 @@ export default (initialState = {}) => ({
* status: {String}, * status: {String},
* summary: { * summary: {
* total: {Number}, * total: {Number},
* notes: {Number}, * resolved: {Number},
* warnings: {Number}, * errored: {Number},
* errors: {Number},
* }, * },
* existing_errors: {Array.<Object>}, * existing_errors: {Array.<Object>},
* existing_notes: {Array.<Object>}, * existing_notes: {Array.<Object>},
......
import { difference, intersection } from 'lodash';
import {
STATUS_FAILED,
STATUS_SUCCESS,
ACCESSIBILITY_ISSUE_ERROR,
ACCESSIBILITY_ISSUE_WARNING,
} from '../../constants';
export const parseAccessibilityReport = data => {
// Combine all issues into one array
return Object.keys(data.results)
.map(key => [...data.results[key]])
.flat()
.map(issue => JSON.stringify(issue)); // stringify to help with comparisons
};
export const compareAccessibilityReports = reports => {
const result = {
status: '',
summary: {
total: 0,
notes: 0,
errors: 0,
warnings: 0,
},
new_errors: [],
new_notes: [],
new_warnings: [],
resolved_errors: [],
resolved_notes: [],
resolved_warnings: [],
existing_errors: [],
existing_notes: [],
existing_warnings: [],
};
const headReport = reports.filter(report => report.isHead)[0];
const baseReport = reports.filter(report => !report.isHead)[0];
// existing issues are those that exist in both the head report and the base report
const existingIssues = intersection(headReport.issues, baseReport.issues);
// new issues are those that exist in only the head report
const newIssues = difference(headReport.issues, baseReport.issues);
// resolved issues are those that exist in only the base report
const resolvedIssues = difference(baseReport.issues, headReport.issues);
const parseIssues = (issue, issueType, shouldCount) => {
const parsedIssue = JSON.parse(issue);
switch (parsedIssue.type) {
case ACCESSIBILITY_ISSUE_ERROR:
result[`${issueType}_errors`].push(parsedIssue);
if (shouldCount) {
result.summary.errors += 1;
}
break;
case ACCESSIBILITY_ISSUE_WARNING:
result[`${issueType}_warnings`].push(parsedIssue);
if (shouldCount) {
result.summary.warnings += 1;
}
break;
default:
result[`${issueType}_notes`].push(parsedIssue);
if (shouldCount) {
result.summary.notes += 1;
}
break;
}
};
existingIssues.forEach(issue => parseIssues(issue, 'existing', true));
newIssues.forEach(issue => parseIssues(issue, 'new', true));
resolvedIssues.forEach(issue => parseIssues(issue, 'resolved', false));
result.summary.total = result.summary.errors + result.summary.warnings + result.summary.notes;
const hasErrorsOrWarnings = result.summary.errors > 0 || result.summary.warnings > 0;
result.status = hasErrorsOrWarnings ? STATUS_FAILED : STATUS_SUCCESS;
return result;
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
...@@ -146,11 +146,7 @@ export default { ...@@ -146,11 +146,7 @@ export default {
}); });
}, },
shouldShowAccessibilityReport() { shouldShowAccessibilityReport() {
return ( return this.mr.accessibilityReportPath && this.glFeatures.accessibilityMergeRequestWidget;
this.accessibilility?.base_path &&
this.accessibilility?.head_path &&
this.glFeatures.accessibilityMergeRequestWidget
);
}, },
}, },
watch: { watch: {
...@@ -396,8 +392,7 @@ export default { ...@@ -396,8 +392,7 @@ export default {
<grouped-accessibility-reports-app <grouped-accessibility-reports-app
v-if="shouldShowAccessibilityReport" v-if="shouldShowAccessibilityReport"
:base-endpoint="mr.accessibility.base_path" :endpoint="mr.accessibilityReportPath"
:head-endpoint="mr.accessibility.head_path"
/> />
<div class="mr-widget-section"> <div class="mr-widget-section">
......
...@@ -103,7 +103,7 @@ export default class MergeRequestStore { ...@@ -103,7 +103,7 @@ export default class MergeRequestStore {
this.ciStatusFaviconPath = pipelineStatus ? pipelineStatus.favicon : null; this.ciStatusFaviconPath = pipelineStatus ? pipelineStatus.favicon : null;
this.terraformReportsPath = data.terraform_reports_path; this.terraformReportsPath = data.terraform_reports_path;
this.testResultsPath = data.test_reports_path; this.testResultsPath = data.test_reports_path;
this.accessibility = data.accessibility || {}; this.accessibilityReportPath = data.accessibility_report_path;
this.exposedArtifactsPath = data.exposed_artifacts_path; this.exposedArtifactsPath = data.exposed_artifacts_path;
this.cancelAutoMergePath = data.cancel_auto_merge_path; this.cancelAutoMergePath = data.cancel_auto_merge_path;
this.canCancelAutomaticMerge = Boolean(data.cancel_auto_merge_path); this.canCancelAutomaticMerge = Boolean(data.cancel_auto_merge_path);
......
...@@ -352,8 +352,7 @@ export default { ...@@ -352,8 +352,7 @@ export default {
<grouped-accessibility-reports-app <grouped-accessibility-reports-app
v-if="shouldShowAccessibilityReport" v-if="shouldShowAccessibilityReport"
:base-endpoint="mr.accessibility.base_endpoint" :endpoint="mr.accessibilityReportPath"
:head-endpoint="mr.accessibility.head_endpoint"
/> />
<div class="mr-widget-section"> <div class="mr-widget-section">
......
...@@ -1069,12 +1069,6 @@ msgstr "" ...@@ -1069,12 +1069,6 @@ msgstr ""
msgid "AccessTokens|reset it" msgid "AccessTokens|reset it"
msgstr "" msgstr ""
msgid "AccessibilityReport|Accessibility report artifact not found"
msgstr ""
msgid "AccessibilityReport|Failed to retrieve accessibility report"
msgstr ""
msgid "AccessibilityReport|Learn More" msgid "AccessibilityReport|Learn More"
msgstr "" msgstr ""
......
...@@ -3,7 +3,7 @@ import Vuex from 'vuex'; ...@@ -3,7 +3,7 @@ import Vuex from 'vuex';
import GroupedAccessibilityReportsApp from '~/reports/accessibility_report/grouped_accessibility_reports_app.vue'; import GroupedAccessibilityReportsApp from '~/reports/accessibility_report/grouped_accessibility_reports_app.vue';
import AccessibilityIssueBody from '~/reports/accessibility_report/components/accessibility_issue_body.vue'; import AccessibilityIssueBody from '~/reports/accessibility_report/components/accessibility_issue_body.vue';
import store from '~/reports/accessibility_report/store'; import store from '~/reports/accessibility_report/store';
import { comparedReportResult } from './mock_data'; import { mockReport } from './mock_data';
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
...@@ -18,8 +18,7 @@ describe('Grouped accessibility reports app', () => { ...@@ -18,8 +18,7 @@ describe('Grouped accessibility reports app', () => {
store: mockStore, store: mockStore,
localVue, localVue,
propsData: { propsData: {
baseEndpoint: 'base_endpoint.json', endpoint: 'endpoint.json',
headEndpoint: 'head_endpoint.json',
}, },
methods: { methods: {
fetchReport: () => {}, fetchReport: () => {},
...@@ -66,8 +65,7 @@ describe('Grouped accessibility reports app', () => { ...@@ -66,8 +65,7 @@ describe('Grouped accessibility reports app', () => {
beforeEach(() => { beforeEach(() => {
mockStore.state.report = { mockStore.state.report = {
summary: { summary: {
errors: 0, errored: 0,
warnings: 0,
}, },
}; };
}); });
...@@ -83,8 +81,7 @@ describe('Grouped accessibility reports app', () => { ...@@ -83,8 +81,7 @@ describe('Grouped accessibility reports app', () => {
beforeEach(() => { beforeEach(() => {
mockStore.state.report = { mockStore.state.report = {
summary: { summary: {
errors: 0, errored: 1,
warnings: 1,
}, },
}; };
}); });
...@@ -100,8 +97,7 @@ describe('Grouped accessibility reports app', () => { ...@@ -100,8 +97,7 @@ describe('Grouped accessibility reports app', () => {
beforeEach(() => { beforeEach(() => {
mockStore.state.report = { mockStore.state.report = {
summary: { summary: {
errors: 1, errored: 2,
warnings: 1,
}, },
}; };
}); });
...@@ -115,18 +111,15 @@ describe('Grouped accessibility reports app', () => { ...@@ -115,18 +111,15 @@ describe('Grouped accessibility reports app', () => {
describe('with issues to show', () => { describe('with issues to show', () => {
beforeEach(() => { beforeEach(() => {
mockStore.state.report = comparedReportResult; mockStore.state.report = mockReport;
}); });
it('renders custom accessibility issue body', () => { it('renders custom accessibility issue body', () => {
const issueBody = wrapper.find(AccessibilityIssueBody); const issueBody = wrapper.find(AccessibilityIssueBody);
expect(issueBody.props('issue').name).toEqual(comparedReportResult.new_errors[0].name); expect(issueBody.props('issue').code).toBe(mockReport.new_errors[0].code);
expect(issueBody.props('issue').code).toEqual(comparedReportResult.new_errors[0].code); expect(issueBody.props('issue').message).toBe(mockReport.new_errors[0].message);
expect(issueBody.props('issue').message).toEqual( expect(issueBody.props('isNew')).toBe(true);
comparedReportResult.new_errors[0].message,
);
expect(issueBody.props('isNew')).toEqual(true);
}); });
}); });
}); });
......
export const baseReport = { export const mockReport = {
results: {
'http://about.gitlab.com/users/sign_in': [
{
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 2.82:1. Recommendation: change background to #d1470c.',
context:
'<a class="btn btn-nav-cta btn-nav-link-cta" href="/free-trial">\nGet free trial\n</a>',
selector: '#main-nav > div:nth-child(2) > ul > div:nth-child(8) > a',
runner: 'htmlcs',
runnerExtras: {},
},
],
'https://about.gitlab.com': [
{
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: {},
},
],
},
};
export const parsedBaseReport = [
'{"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 2.82:1. Recommendation: change background to #d1470c.","context":"<a class=\\"btn btn-nav-cta btn-nav-link-cta\\" href=\\"/free-trial\\">\\nGet free trial\\n</a>","selector":"#main-nav > div:nth-child(2) > ul > div:nth-child(8) > a","runner":"htmlcs","runnerExtras":{}}',
'{"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":{}}',
];
export const headReport = {
results: {
'http://about.gitlab.com/users/sign_in': [
{
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: {},
},
],
'https://about.gitlab.com': [
{
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: {},
},
],
},
};
export const comparedReportResult = {
status: 'failed', status: 'failed',
summary: { summary: {
total: 2, total: 2,
notes: 0, resolved: 0,
errors: 2, errored: 2,
warnings: 0,
}, },
new_errors: [headReport.results['http://about.gitlab.com/users/sign_in'][0]], 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_notes: [],
new_warnings: [], new_warnings: [],
resolved_errors: [baseReport.results['http://about.gitlab.com/users/sign_in'][0]], 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_notes: [],
resolved_warnings: [], resolved_warnings: [],
existing_errors: [headReport.results['https://about.gitlab.com'][0]], 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_notes: [],
existing_warnings: [], existing_warnings: [],
}; };
export default () => {};
...@@ -5,7 +5,7 @@ import * as types from '~/reports/accessibility_report/store/mutation_types'; ...@@ -5,7 +5,7 @@ import * as types from '~/reports/accessibility_report/store/mutation_types';
import createStore from '~/reports/accessibility_report/store'; import createStore from '~/reports/accessibility_report/store';
import { TEST_HOST } from 'spec/test_constants'; import { TEST_HOST } from 'spec/test_constants';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import { baseReport, headReport, comparedReportResult } from '../mock_data'; import { mockReport } from '../mock_data';
describe('Accessibility Reports actions', () => { describe('Accessibility Reports actions', () => {
let localState; let localState;
...@@ -18,14 +18,13 @@ describe('Accessibility Reports actions', () => { ...@@ -18,14 +18,13 @@ describe('Accessibility Reports actions', () => {
describe('setEndpoints', () => { describe('setEndpoints', () => {
it('should commit SET_ENDPOINTS mutation', done => { it('should commit SET_ENDPOINTS mutation', done => {
const baseEndpoint = 'base_endpoint.json'; const endpoint = 'endpoint.json';
const headEndpoint = 'head_endpoint.json';
testAction( testAction(
actions.setEndpoints, actions.setEndpoint,
{ baseEndpoint, headEndpoint }, endpoint,
localState, localState,
[{ type: types.SET_ENDPOINTS, payload: { baseEndpoint, headEndpoint } }], [{ type: types.SET_ENDPOINT, payload: endpoint }],
[], [],
done, done,
); );
...@@ -36,37 +35,14 @@ describe('Accessibility Reports actions', () => { ...@@ -36,37 +35,14 @@ describe('Accessibility Reports actions', () => {
let mock; let mock;
beforeEach(() => { beforeEach(() => {
localState.baseEndpoint = `${TEST_HOST}/endpoint.json`; localState.endpoint = `${TEST_HOST}/endpoint.json`;
localState.headEndpoint = `${TEST_HOST}/endpoint.json`;
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
}); });
afterEach(() => { afterEach(() => {
mock.restore(); mock.restore();
}); actions.stopPolling();
actions.clearEtagPoll();
describe('when no endpoints are given', () => {
beforeEach(() => {
localState.baseEndpoint = null;
localState.headEndpoint = null;
});
it('should commit REQUEST_REPORT and RECEIVE_REPORT_ERROR mutations', done => {
testAction(
actions.fetchReport,
null,
localState,
[
{ type: types.REQUEST_REPORT },
{
type: types.RECEIVE_REPORT_ERROR,
payload: 'Accessibility report artifact not found',
},
],
[],
done,
);
});
}); });
describe('success', () => { describe('success', () => {
...@@ -81,7 +57,7 @@ describe('Accessibility Reports actions', () => { ...@@ -81,7 +57,7 @@ describe('Accessibility Reports actions', () => {
[{ type: types.REQUEST_REPORT }], [{ type: types.REQUEST_REPORT }],
[ [
{ {
payload: [{ ...data, isHead: false }, { ...data, isHead: true }], payload: { status: 200, data },
type: 'receiveReportSuccess', type: 'receiveReportSuccess',
}, },
], ],
...@@ -98,14 +74,8 @@ describe('Accessibility Reports actions', () => { ...@@ -98,14 +74,8 @@ describe('Accessibility Reports actions', () => {
actions.fetchReport, actions.fetchReport,
null, null,
localState, localState,
[ [{ type: types.REQUEST_REPORT }],
{ type: types.REQUEST_REPORT }, [{ type: 'receiveReportError' }],
{
type: types.RECEIVE_REPORT_ERROR,
payload: 'Failed to retrieve accessibility report',
},
],
[],
done, done,
); );
}); });
...@@ -113,13 +83,37 @@ describe('Accessibility Reports actions', () => { ...@@ -113,13 +83,37 @@ describe('Accessibility Reports actions', () => {
}); });
describe('receiveReportSuccess', () => { describe('receiveReportSuccess', () => {
it('should commit RECEIVE_REPORT_SUCCESS mutation', done => { 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( testAction(
actions.receiveReportSuccess, actions.receiveReportSuccess,
[{ ...baseReport, isHead: false }, { ...headReport, isHead: true }], { status: 204, data: mockReport },
localState, localState,
[{ type: types.RECEIVE_REPORT_SUCCESS, payload: comparedReportResult }],
[], [],
[],
done,
);
});
});
describe('receiveReportError', () => {
it('should commit RECEIVE_REPORT_ERROR mutation', done => {
testAction(
actions.receiveReportError,
null,
localState,
[{ type: types.RECEIVE_REPORT_ERROR }],
[{ type: 'stopPolling' }],
done, done,
); );
}); });
......
...@@ -67,8 +67,7 @@ describe('Accessibility reports store getters', () => { ...@@ -67,8 +67,7 @@ describe('Accessibility reports store getters', () => {
it('returns summary message containing number of errors', () => { it('returns summary message containing number of errors', () => {
localState.report = { localState.report = {
summary: { summary: {
errors: 1, errored: 2,
warnings: 1,
}, },
}; };
const result = 'Accessibility scanning detected 2 issues for the source branch only'; const result = 'Accessibility scanning detected 2 issues for the source branch only';
...@@ -81,8 +80,7 @@ describe('Accessibility reports store getters', () => { ...@@ -81,8 +80,7 @@ describe('Accessibility reports store getters', () => {
it('returns summary message containing no errors', () => { it('returns summary message containing no errors', () => {
localState.report = { localState.report = {
summary: { summary: {
errors: 0, errored: 0,
warnings: 0,
}, },
}; };
const result = 'Accessibility scanning detected no issues for the source branch only'; const result = 'Accessibility scanning detected no issues for the source branch only';
...@@ -108,7 +106,7 @@ describe('Accessibility reports store getters', () => { ...@@ -108,7 +106,7 @@ describe('Accessibility reports store getters', () => {
it('returns false', () => { it('returns false', () => {
localState.report = { localState.report = {
status: 'success', status: 'success',
summary: { errors: 0, warnings: 0 }, summary: { errored: 0 },
}; };
expect(getters.shouldRenderIssuesList(localState)).toEqual(false); expect(getters.shouldRenderIssuesList(localState)).toEqual(false);
......
...@@ -10,17 +10,12 @@ describe('Accessibility Reports mutations', () => { ...@@ -10,17 +10,12 @@ describe('Accessibility Reports mutations', () => {
localState = localStore.state; localState = localStore.state;
}); });
describe('SET_ENDPOINTS', () => { describe('SET_ENDPOINT', () => {
it('sets base and head endpoints to give values', () => { it('sets endpoint to given value', () => {
const baseEndpoint = 'base_endpoint.json'; const endpoint = 'endpoint.json';
const headEndpoint = 'head_endpoint.json'; mutations.SET_ENDPOINT(localState, endpoint);
mutations.SET_ENDPOINTS(localState, {
baseEndpoint, expect(localState.endpoint).toEqual(endpoint);
headEndpoint,
});
expect(localState.baseEndpoint).toEqual(baseEndpoint);
expect(localState.headEndpoint).toEqual(headEndpoint);
}); });
}); });
...@@ -65,11 +60,5 @@ describe('Accessibility Reports mutations', () => { ...@@ -65,11 +60,5 @@ describe('Accessibility Reports mutations', () => {
expect(localState.hasError).toEqual(true); expect(localState.hasError).toEqual(true);
}); });
it('sets errorMessage to given message', () => {
mutations.RECEIVE_REPORT_ERROR(localState, 'message');
expect(localState.errorMessage).toEqual('message');
});
}); });
}); });
import * as utils from '~/reports/accessibility_report/store/utils';
import { baseReport, headReport, parsedBaseReport, comparedReportResult } from '../mock_data';
describe('Accessibility Report store utils', () => {
describe('parseAccessibilityReport', () => {
it('returns array of stringified issues', () => {
const result = utils.parseAccessibilityReport(baseReport);
expect(result).toEqual(parsedBaseReport);
});
});
describe('compareAccessibilityReports', () => {
let reports;
beforeEach(() => {
reports = [
{
isHead: false,
issues: utils.parseAccessibilityReport(baseReport),
},
{
isHead: true,
issues: utils.parseAccessibilityReport(headReport),
},
];
});
it('returns the comparison report with a new, resolved, and existing error', () => {
const result = utils.compareAccessibilityReports(reports);
expect(result).toEqual(comparedReportResult);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment