Skip to content
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 69 additions & 24 deletions src/pageScanner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,39 @@ import { getPageDensity } from './helpers/density';

const SCAN_TIMEOUT_IN_SECONDS = 30;

// Hold the timeout for the scan so it can bail on long-running scans.
let tooLongTimeout;

// Read the data passed from the parent document.
const body = document.querySelector( 'body' );
const iframeId = body.getAttribute( 'data-iframe-id' );
const eventName = body.getAttribute( 'data-iframe-event-name' );
const postId = body.getAttribute( 'data-iframe-post-id' );

/**
* Check if the current context the script is loaded in is a scanner iframe.
*
* @return {boolean} True if in iframe context, false otherwise.
*/
function isIframeContext() {
return !! ( body && body.hasAttribute( 'data-iframe-id' ) && body.hasAttribute( 'data-iframe-event-name' ) );
}

/**
* Get the iframe options from the body attributes/
*
* @return {Object} {{configOptions: {}, runOptions: {}, iframeId: string | Attribute, eventName: string | Attribute, postId: string | Attribute}}
*/
function getIframeOptions() {
return {
configOptions: {},
runOptions: {},
iframeId: body.getAttribute( 'data-iframe-id' ),
eventName: body.getAttribute( 'data-iframe-event-name' ),
postId: body.getAttribute( 'data-iframe-post-id' ),
};
}

const scan = async (
options = { configOptions: {}, runOptions: {} }
) => {
Expand Down Expand Up @@ -58,9 +85,10 @@ const scan = async (
//Build an array of the dom selectors and ruleIDs for violations/failed tests
item.violations.forEach( ( violation ) => {
if ( violation.result === 'failed' ) {
const el = document.querySelector( violation.node.selector );
violations.push( {
selector: violation.node.selector,
html: document.querySelector( violation.node.selector ).outerHTML,
html: el ? el.outerHTML : null,
ruleId: item.id,
impact: item.impact,
tags: item.tags,
Expand All @@ -71,9 +99,10 @@ const scan = async (
// Handle incomplete results for form-field-multiple-labels only.
if ( item.id === 'form-field-multiple-labels' ) { // Allow incomplete results for this rule.
item.incomplete.forEach( ( incompleteItem ) => {
const el = document.querySelector( incompleteItem.node.selector );
violations.push( {
selector: incompleteItem.node.selector,
html: document.querySelector( incompleteItem.node.selector ).outerHTML,
html: el ? el.outerHTML : null,
ruleId: item.id,
impact: item.impact,
tags: item.tags,
Expand Down Expand Up @@ -153,38 +182,54 @@ const onDone = ( violations = [], errorMsgs = [], error = false ) => {
function() {
axe.teardown();
axe = null;

dispatchDoneEvent( violations, errorMsgs, error );
dispatchDoneEvent( violations, errorMsgs, '' );
},
function() {
axe.teardown();
axe = null;

// Create a custom event
errorMsgs.push( '***** axe.cleanup() failed.' );

dispatchDoneEvent( violations, errorMsgs, error );
dispatchDoneEvent( violations, errorMsgs, 'cleanup-failed' );
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}
);
} else {
error = true;

errorMsgs.push( '***** axe.cleanup() does not exist.' );
axe = null;

dispatchDoneEvent( violations, errorMsgs, error );
dispatchDoneEvent( violations, errorMsgs, 'cleanup-not-exists' );
}
};

// Fire a failed event if the scan doesn't complete on time.
const tooLongTimeout = setTimeout( function() {
onDone( [], [ '***** axe scan took too long.' ], true );
}, SCAN_TIMEOUT_IN_SECONDS * 1000 );

// Start the scan.
scan().then( ( results ) => {
const violations = JSON.parse( JSON.stringify( results.violations ) );
onDone( violations );
} ).catch( ( err ) => {
onDone( [], [ err.message ], true );
} );
/**
* Attach an axe runner to the window object to allow for running the scan from
* the active document.
*
* @param {Object} options Options for the accessibility scan.
* @return {Promise<Object>} Promise resolving to the scan result.
*/
window.runAccessibilityScan = async function( options = {} ) {
return scan( options )
.then( ( result ) => {
if ( typeof options.onComplete === 'function' ) {
options.onComplete( result );
}
return result;
} )
.catch( ( err ) => {
if ( typeof options.onComplete === 'function' ) {
options.onComplete( null, err );
}
throw err;
Comment thread
pattonwebz marked this conversation as resolved.
} );
};

// Auto-run scan and dispatch event to parent frame if in iframe context
if ( isIframeContext() ) {
const iframeOptions = getIframeOptions();

tooLongTimeout = setTimeout( () => {
dispatchDoneEvent( [], [ 'Scan timed out' ], 'timeout' );
}, SCAN_TIMEOUT_IN_SECONDS * 1000 );

scan( iframeOptions )
.then( ( result ) => onDone( result.violations, [], null ) )
.catch( ( err ) => onDone( [], [ err.message || 'Unknown error' ], err.message ) );
}