From 78543b4a2d8c1bcc77784ea8369a5af997b428ad Mon Sep 17 00:00:00 2001 From: Matt Isner Date: Tue, 10 Oct 2017 12:10:17 -0400 Subject: [PATCH] perf(reporter): add option to limit result types to be processed Closes #512 https://github.com/dequelabs/axe-core/issues/512 --- .../reporters/helpers/process-aggregate.js | 28 ++ lib/core/reporters/no-passes.js | 3 + .../reporters/helpers/process-aggregate.js | 246 ++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 test/core/reporters/helpers/process-aggregate.js diff --git a/lib/core/reporters/helpers/process-aggregate.js b/lib/core/reporters/helpers/process-aggregate.js index f72f5e9991..e124df749d 100644 --- a/lib/core/reporters/helpers/process-aggregate.js +++ b/lib/core/reporters/helpers/process-aggregate.js @@ -27,6 +27,30 @@ function normalizeRelatedNodes(node, options) { } var resultKeys = axe.constants.resultGroups; + +/** + * Configures the processing of axe results. + * + * @typedef ProcessOptions + * @property {Array} resultsTypes limit the types of results to process ('passes', 'violations', etc.) + * @property {Boolean} elementRef display node's element references + * @property {Boolean} selectors display node's selectors + * @property {Boolean} xpath display node's xpaths + */ + +/** + * Aggregrate and process the aXe results, + * adding desired data to nodes and relatedNodes in each rule result. + * + * Prepares result data for reporters. + * + * @method processAggregate + * @memberof helpers + * @param {Array} results + * @param {ProcessOptions} options + * @return {Object} + * + */ helpers.processAggregate = function (results, options) { var resultObject = axe.utils.aggregateResult(results); @@ -34,6 +58,10 @@ helpers.processAggregate = function (results, options) { resultObject.url = window.location.href; resultKeys.forEach(function (key) { + if (options.resultTypes && !options.resultTypes.includes(key)) { + delete resultObject[key]; + return; + } resultObject[key] = (resultObject[key] || []).map(function (ruleResult) { ruleResult = Object.assign({}, ruleResult); diff --git a/lib/core/reporters/no-passes.js b/lib/core/reporters/no-passes.js index be32c2d956..f23b2f0d12 100644 --- a/lib/core/reporters/no-passes.js +++ b/lib/core/reporters/no-passes.js @@ -5,6 +5,9 @@ axe.addReporter('no-passes', function (results, options, callback) { callback = options; options = {}; } + // limit result processing to types we want to include in the output + options.resultTypes = ['violations']; + var out = helpers.processAggregate(results, options); callback({ diff --git a/test/core/reporters/helpers/process-aggregate.js b/test/core/reporters/helpers/process-aggregate.js new file mode 100644 index 0000000000..0a62c066a5 --- /dev/null +++ b/test/core/reporters/helpers/process-aggregate.js @@ -0,0 +1,246 @@ + +describe('helpers.processAggregate', function () { + 'use strict'; + var results, options; + + beforeEach(function () { + results = [{ + id: 'passed-rule', + passes: [{ + result: 'passed', + node: { + element: document.createElement('div'), + selector: 'header > .thing', + source: '
Thing
', + xpath: '/header/div[@class="thing"]' + }, + any: [{ + id: 'passed-rule', + relatedNodes: [{ + element: document.createElement('div'), + selector: 'footer > .thing', + source: '
Thing
', + xpath: '/footer/div[@class="thing"]', + }] + }], + all: [], + none: [] + }], + inapplicable: [], + incomplete: [], + violations: [] + }, { + id: 'failed-rule', + violations: [{ + result: 'failed', + node: { + selector: '#dopel', + source: '', + xpath: '/main/input[@id="dopel"]', + fromFrame: true + }, + any: [{ + id: 'failed-rule', + relatedNodes: [{ + element: document.createElement('input'), + selector: '#dopel', + source: '', + xpath: '/main/input[@id="dopel"]', + fromFrame: true + }] + }], + all: [], + none: [] + }], + inapplicable: [], + passes: [], + incomplete: [] + }]; + }); + + it('should add a `timestamp` property to the `resultObject`', function () { + var resultObject = helpers.processAggregate(results, {}); + assert.isDefined(resultObject.timestamp); + }); + + it('should add a `url` property to the `resultObject`', function () { + var resultObject = helpers.processAggregate(results, {}); + assert.isDefined(resultObject.url); + }); + + it('should remove the `result` property from each node in each ruleResult', function () { + assert.isDefined(results.find(function (r) { + return r.id === 'passed-rule'; + }).passes[0].result); + + var resultObject = helpers.processAggregate(results, {}); + var ruleResult = resultObject.passes.find(function (r) { + return r.id === 'passed-rule'; + }); + assert.isUndefined(ruleResult.nodes[0].result); + }); + + it('should remove the `node` property from each node in each ruleResult', function () { + assert.isDefined(results.find(function (r) { + return r.id === 'passed-rule'; + }).passes[0].node); + + var resultObject = helpers.processAggregate(results, {}); + var ruleResult = resultObject.passes.find(function (r) { + return r.id === 'passed-rule'; + }); + assert.isUndefined(ruleResult.nodes[0].node); + }); + + describe('`options` argument', function () { + + describe('`resultTypes` option', function () { + + it('should remove non-specified result types from the `resultObject`', function () { + var resultObject = helpers.processAggregate(results, { resultTypes: ['passes', 'violations'] }); + assert.isDefined(resultObject.passes); + assert.isDefined(resultObject.violations); + assert.isUndefined(resultObject.incomplete); + assert.isUndefined(resultObject.inapplicable); + }); + }); + + describe('`elementRef` option', function () { + + describe('when set to true', function () { + + before(function () { + options = { elementRef: true }; + }); + + describe('when node\'s, or relatedNode\'s, `fromFrame` equals false', function () { + it('should add an `element` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isDefined(resultObject.passes[0].nodes[0].element); + assert.isDefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].element); + }); + }); + + describe('when node\'s, or relatedNode\'s, `fromFrame` equals true', function () { + it('should NOT add an `element` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isUndefined(resultObject.violations[0].nodes[0].element); + assert.isUndefined(resultObject.violations[0].nodes[0].any[0].relatedNodes[0].element); + }); + }); + }); + + describe('when set to false', function () { + + before(function () { + options = { elementRef: false }; + }); + + it('should NOT add an `element` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isUndefined(resultObject.passes[0].nodes[0].element); + assert.isUndefined(resultObject.violations[0].nodes[0].element); + assert.isUndefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].element); + assert.isUndefined(resultObject.violations[0].nodes[0].any[0].relatedNodes[0].element); + }); + }); + + describe('when not set at all', function () { + + it('should NOT add an `element` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, {}); + assert.isUndefined(resultObject.passes[0].nodes[0].element); + assert.isUndefined(resultObject.violations[0].nodes[0].element); + assert.isUndefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].element); + assert.isUndefined(resultObject.violations[0].nodes[0].any[0].relatedNodes[0].element); + }); + }); + }); + + describe('`selectors` option', function () { + + describe('when set to false', function () { + + before(function () { + options = { selectors: false }; + }); + + describe('when node\'s, or relatedNode\'s, `fromFrame` equals true', function () { + it('should add a `target` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isDefined(resultObject.violations[0].nodes[0].target); + assert.isDefined(resultObject.violations[0].nodes[0].any[0].relatedNodes[0].target); + }); + }); + + describe('when node\'s, or relatedNode\'s, `fromFrame` equals false', function () { + it('should NOT add a `target` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isUndefined(resultObject.passes[0].nodes[0].target); + assert.isUndefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].target); + }); + }); + }); + + describe('when set to true', function () { + + before(function () { + options = { selectors: true }; + }); + + it('should add a `target` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isDefined(resultObject.passes[0].nodes[0].target); + assert.isDefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].target); + }); + }); + + describe('when not set at all', function () { + + it('should add a `target` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, {}); + assert.isDefined(resultObject.passes[0].nodes[0].target); + assert.isDefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].target); + }); + }); + }); + + describe('`xpath` option', function () { + + describe('when set to true', function () { + + before(function () { + options = { xpath: true }; + }); + + it('should add an `xpath` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isDefined(resultObject.passes[0].nodes[0].xpath); + assert.isDefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].xpath); + }); + }); + + describe('when set to false', function () { + + before(function () { + options = { xpath: false }; + }); + + it('should NOT add an `xpath` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, options); + assert.isUndefined(resultObject.passes[0].nodes[0].xpath); + assert.isUndefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].xpath); + }); + }); + + describe('when not set at all', function () { + + it('should NOT add an `xpath` property to the subResult nodes or relatedNodes', function () { + var resultObject = helpers.processAggregate(results, {}); + assert.isUndefined(resultObject.passes[0].nodes[0].xpath); + assert.isUndefined(resultObject.passes[0].nodes[0].any[0].relatedNodes[0].xpath); + }); + }); + }); + }); +});