Skip to content

Instantly share code, notes, and snippets.

@greg-randall
Created August 24, 2023 15:47
Show Gist options
  • Save greg-randall/6b8ee6140a5b7be4090e9e80014ac8fa to your computer and use it in GitHub Desktop.
Save greg-randall/6b8ee6140a5b7be4090e9e80014ac8fa to your computer and use it in GitHub Desktop.
Generate a screenshot and csv of A11y errors from a list of URLs.
//pass a text file with one url per line:
//node wave-screenshotter.js urls.txt
const fs = require( 'fs' );
//get the arguments from the terminal
const myArgs = process.argv.slice( 2 );
const input_filename = myArgs[ 0 ];
var dt = new Date(); // gonna do all the dates and times up here so that each read is at the same date and time
date_time = `${dt.getMonth()}-${dt.getDate()}-${dt.getFullYear()}_${dt.getUTCHours()}-${dt.getUTCMinutes()}UTC`;
//write out a header for the error csv
fs.appendFile( `error-counts_${date_time}.csv`, "URL,Date Time,Errors,Contrast Errors,Alerts,Features,Structural Elements,ARIA,Screenshot Filename,\n", ( err ) => {
if ( err ) throw err;
} );
function timeout( ms ) {
return new Promise( resolve => setTimeout( resolve, ms ) );
};
// get puppeteer setup
const puppeteer = require( 'puppeteer-extra' );
const pluginStealth = require( 'puppeteer-extra-plugin-stealth' )();
puppeteer.use( pluginStealth );
( async () => {
const browser = await puppeteer.launch( {
headless: 'new'
} );
const page = await browser.newPage();
await page.setViewport( {
width: 1920,
height: 1080,
deviceScaleFactor: 2
} );
// get our input list of urls
const readline = require( 'readline' );
const fileStream = fs.createReadStream( input_filename );
const rl = readline.createInterface( {
input: fileStream,
crlfDelay: Infinity
} );
i = 1; //count the number of sites we've looked at
var shell = require( 'shelljs' );
var url_count = shell.exec( `sed -n '$=' ${input_filename}`, {
async: false,
silent: true
} )
.stdout; //using sed to do this seems a bit silly, but i think is faster and shorter than other options
for await ( var url of rl ) { //loop through our list
//process url so that we can use it in the filename
url = new URL( url );
url_path = url.hostname + url.pathname;
url_path = url_path.replace( /\/$/g, '' );
url_path = url_path.replace( /\//g, '--' );
url_path = url_path.replace( /[^a-zA-Z0-9-]/g, '_' );
output_file = `${url_path}__${date_time}.jpg`;
console.log( `${i}/${url_count.trim()} ${url}` ); // show progress
i++;
//load our page
await page.goto( `https://wave.webaim.org/report#/${url}`, {
timeout: 15000,
waitUntil: [ 'domcontentloaded' ],
} );
await timeout( 1000 ); //we need this pause because, the page loads, and then starts trying to get the page we're running an audit on and throws a loading icon
await page.waitForSelector( "#wave5_loading", {
hidden: true
} ); //wait for the loading icon to disappear
await page.click( '[id="tab-details"]' ); //click the errors tab
await timeout( 500 ); // wait a moment for the tab to load
// Capture screenshot
await page.screenshot( {
path: output_file
} );
//get the error numbers from the page
const element = await page.$( "#numbers" ); //get the table by grabbing the surrounding div
var text = await ( await element.getProperty( "innerText" ) )
.jsonValue(); //put the text out of the table
text = text.trim();
text = text.split( "\n" ); //split the raw text into an array
csv_line = `${url},${dt.toISOString()},`; //start building our csv line with the url and the timestamp
text.forEach( async ( wave_error ) => { //loop through all the error lines
wave_error = wave_error.replace( /[^0-9]/g, '' ); //remove everything that isn't a number
csv_line += `${wave_error},`; // add the error to the csv line
} );
csv_line += `${output_file},\n`; // add the output filename in case we want to reference it
fs.appendFile( `error-counts_${date_time}.csv`, csv_line, ( err ) => {
if ( err ) throw err;
} ); //append the csv line
}
browser.close();
} )();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment