Skip to content

Commit

Permalink
Merge pull request #84 from browserstack/release-2.4.0
Browse files Browse the repository at this point in the history
Release 2.4.0
  • Loading branch information
ansh21 authored Aug 27, 2024
2 parents 0b2f622 + 8c0d988 commit d9f41e0
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 5 deletions.
8 changes: 5 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = function (grunt) {
grunt.loadTasks('build/tasks');

var langs;
var wrapper = !!grunt.option('wrapper');
if (grunt.option('lang')) {
langs = (grunt.option('lang') || '').split(/[,;]/g).map(function (lang) {
lang = lang.trim();
Expand Down Expand Up @@ -85,11 +86,11 @@ module.exports = function (grunt) {
files: langs.map(function (lang, i) {
return {
src: [
'lib/intro.stub',
wrapper ? 'lib/custom/intro.stub' : 'lib/intro.stub',
'<%= concat.engine.coreFiles %>',
// include rules / checks / commons
'<%= configure.rules.files[' + i + '].dest.auto %>',
'lib/outro.stub'
wrapper ? 'lib/custom/outro.stub' : 'lib/outro.stub'
],
dest: 'axe' + lang + '.js'
};
Expand Down Expand Up @@ -127,7 +128,8 @@ module.exports = function (grunt) {
entry: 'lib/commons/aria/index.js',
destFile: 'doc/aria-supported.md',
options: {
langs: langs
langs: langs,
wrapper: wrapper
},
listType: 'unsupported' // Possible values for listType: 'supported', 'unsupported', 'all'
}
Expand Down
3 changes: 2 additions & 1 deletion build/tasks/aria-supported.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ module.exports = function (grunt) {
* hence cannot be required at the top of the file.
*/
const done = this.async();
const { langs } = this.options();
const { langs, wrapper } = this.options();
if (wrapper) return true;
const fileNameSuffix = langs && langs.length > 0 ? `${langs[0]}` : '';
const axe = require(`../../axe${fileNameSuffix}`);
const listType = this.data.listType.toLowerCase();
Expand Down
17 changes: 17 additions & 0 deletions lib/core/public/load.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/*global a11yEngine*/
import Audit from '../base/audit';
import cleanup from './cleanup';
import runRules from './run-rules';
import respondable from '../utils/respondable';
import nodeSerializer from '../utils/node-serializer';
import mergeErrors from '../utils/merge-errors';

/**
* Sets up Rules, Messages and default options for Checks, must be invoked before attempting analysis
Expand Down Expand Up @@ -36,6 +38,21 @@ function runCommand(data, keepalive, callback) {
(results, cleanupFn) => {
// Serialize all DqElements
results = nodeSerializer.mapRawResults(results);

//a11y-engine iframe rules error merging logic
const errors = a11yEngine.getErrors();
if (Object.keys(errors).length !== 0) {
if (results[results.length - 1].a11yEngineErrors) {
const error = results.pop();
delete error.a11yEngineErrors;
const mergedErrors = mergeErrors(error, errors);
results.push({ ...mergedErrors, a11yEngineErrors: true });
} else {
results.push({ ...errors, a11yEngineErrors: true });
}
}
a11yEngine.clearErrors();

resolve(results);
// Cleanup AFTER resolve so that selectors can be generated
cleanupFn();
Expand Down
14 changes: 14 additions & 0 deletions lib/core/public/run-rules.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*global a11yEngine*/
import Context from '../base/context';
import teardown from './teardown';
import {
Expand Down Expand Up @@ -36,6 +37,12 @@ export default function runRules(context, options, resolve, reject) {
performanceTimer.auditStart();
}

// If advanced run for iframes is true then setup socket for iframes
if (options.a11yEngineConfig && options.a11yEngineConfig.iframesAdvancedRun) {
a11yEngine.setup(options.a11yEngineConfig);
}

// If run for iframes is true then collect results from iframes
if (context.frames.length && options.iframes !== false) {
q.defer((res, rej) => {
collectResultsFromFrames(context, options, 'rules', null, res, rej);
Expand All @@ -59,6 +66,13 @@ export default function runRules(context, options, resolve, reject) {

// after should only run once, so ensure we are in the top level window
if (context.initiator) {
// Return a11y-engine errors when at top level window
if (results[results.length - 1].a11yEngineErrors) {
const error = results.pop();
delete error.a11yEngineErrors;
a11yEngine.mergeErrors(error);
}

results = audit.after(results, options);

results.forEach(publishMetaData);
Expand Down
8 changes: 8 additions & 0 deletions lib/core/utils/collect-results-from-frames.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export default function collectResultsFromFrames(
// elementRefs can't be passed across frame boundaries
options = { ...options, elementRef: false };

// check a11yengine iframe advance run flag
if (
options.a11yEngineConfig &&
options.a11yEngineConfig.iframesAdvancedRun === false
) {
options.a11yEngineConfig.iframesAdvancedRun = true;
}

var q = queue();
var frames = parentContent.frames;

Expand Down
52 changes: 52 additions & 0 deletions lib/core/utils/merge-errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Function to merge errors for a11y-engine.
// Handles errors differently for check_errors and other errors.
// It also adds the target selector to the errors for better identification.

function mergeErrors(mergedErrors, frameErrors, frameSpec) {
for (const [key, value] of Object.entries(frameErrors)) {
if (key === 'check_errors') {
if (!mergedErrors[key]) {
mergedErrors[key] = {};
}

for (const [checkNameKey, checkNameValue] of Object.entries(value)) {
// Add the target if not present. If present then append parents target.
checkNameValue.forEach(checkNameValueError => {
if (!checkNameValueError.target && frameSpec) {
checkNameValueError.target = frameSpec?.selector;
} else if (checkNameValueError.target && frameSpec) {
checkNameValueError.target = [
...frameSpec.selector,
...checkNameValueError.target
];
}
});
if (mergedErrors[key][checkNameKey]) {
mergedErrors[key][checkNameKey].push(...checkNameValue);
} else {
mergedErrors[key][checkNameKey] = Array.isArray(checkNameValue)
? [...checkNameValue]
: [checkNameValue];
}
}
} else {
// Add the target if not present. If present then append parents target.
value.forEach(errorValue => {
if (!errorValue.target && frameSpec) {
errorValue.target = frameSpec?.selector;
} else if (errorValue.target && frameSpec) {
errorValue.target = [...frameSpec.selector, ...errorValue.target];
}
});
if (mergedErrors[key]) {
mergedErrors[key] = [...mergedErrors[key], ...value];
} else {
mergedErrors[key] = value;
}
}
}

return mergedErrors;
}

export default mergeErrors;
16 changes: 15 additions & 1 deletion lib/core/utils/merge-results.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import nodeSerializer from './node-serializer';
import getAllChecks from './get-all-checks';
import findBy from './find-by';
import mergeErrors from './merge-errors';

/**
* Adds the owning frame's CSS selector onto each instance of DqElement
Expand Down Expand Up @@ -75,13 +76,22 @@ function normalizeResult(result) {
*/
function mergeResults(frameResults, options) {
const mergedResult = [];
// A11yEngine merged errors
let mergedErrors = {};
frameResults.forEach(frameResult => {
const results = normalizeResult(frameResult);
if (!results || !results.length) {
return;
}

const frameSpec = getFrameSpec(frameResult);
// Extract existing errors and merge with new ones
if (results[results.length - 1].a11yEngineErrors) {
const error = results.pop();
delete error.a11yEngineErrors;
mergedErrors = mergeErrors(mergedErrors, error, frameSpec);
}

results.forEach(ruleResult => {
if (ruleResult.nodes && frameSpec) {
pushFrame(ruleResult.nodes, options, frameSpec);
Expand All @@ -106,7 +116,11 @@ function mergeResults(frameResults, options) {
});
}
});
return mergedResult;

if (Object.keys(mergedErrors).length === 0) {
return mergedResult;
}
return [...mergedResult, { ...mergedErrors, a11yEngineErrors: true }];
}

function nodeIndexSort(nodeIndexesA = [], nodeIndexesB = []) {
Expand Down
15 changes: 15 additions & 0 deletions lib/custom/intro.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*! axe v<%= pkg.version %>
* Copyright (c) 2015 - <%= grunt.template.today("yyyy") %> Deque Systems, Inc.
*
* Your use of this Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This entire copyright notice must appear in every copy of this file you
* distribute or in any file that contains substantial portions of this source
* code.
*/
const createAxe = () => (function axeFunction (window) {
// A window reference is required to access the axe object in a "global".
var global = window;
var document = window.document;
2 changes: 2 additions & 0 deletions lib/custom/outro.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

}( typeof window === 'object' ? window : this ));
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"develop": "grunt dev --force",
"api-docs": "jsdoc --configure .jsdoc.json",
"build": "grunt",
"build:wrapper": "grunt --wrapper=true",
"eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js'",
"test": "npm run test:tsc && run-s \"test:unit:* -- {@}\" --",
"test:tsc": "tsc",
Expand Down

0 comments on commit d9f41e0

Please sign in to comment.