diff --git a/mergeAxeResults.js b/mergeAxeResults.js index 6b9e8951..98f0a302 100644 --- a/mergeAxeResults.js +++ b/mergeAxeResults.js @@ -35,7 +35,7 @@ const writeResults = async (allissues, storagePath, jsonFilename = 'compiledResu const finalResultsInJson = JSON.stringify(allissues, null, 4); const passedItemsJson = {}; - + allissues.items.passed.rules.forEach(r => { passedItemsJson[r.description] = { totalOccurrencesInScan: r.totalItems, @@ -45,13 +45,16 @@ const writeResults = async (allissues, storagePath, jsonFilename = 'compiledResu url: p.url, totalOccurrencesInPage: p.items.length, occurrences: p.items, - })) - } + })), + }; }); try { await fs.writeFile(`${storagePath}/reports/${jsonFilename}.json`, finalResultsInJson); - await fs.writeFile(`${storagePath}/reports/passed_items.json`, JSON.stringify(passedItemsJson, null, 4)); + await fs.writeFile( + `${storagePath}/reports/passed_items.json`, + JSON.stringify(passedItemsJson, null, 4), + ); } catch (writeResultsError) { consoleLogger.info( 'An error has occurred when compiling the results into the report, please try again.', diff --git a/package-lock.json b/package-lock.json index 1613894f..eac178da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "purple-hats", - "version": "0.0.12", + "version": "0.0.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "purple-hats", - "version": "0.0.12", + "version": "0.0.13", "license": "ISC", "dependencies": { "axe-core": "^4.6.2", diff --git a/package.json b/package.json index cb52fd95..4f95cda2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "purple-hats", "main": "index.js", - "version": "0.0.12", + "version": "0.0.13", "type": "module", "imports": { "#root/*.js": "./*.js" diff --git a/playwrightAxeGenerator.js b/playwrightAxeGenerator.js index d3e8d77e..7f71515b 100644 --- a/playwrightAxeGenerator.js +++ b/playwrightAxeGenerator.js @@ -8,7 +8,6 @@ import { devices } from 'playwright'; import { consoleLogger, silentLogger } from './logs.js'; const playwrightAxeGenerator = async (domain, data) => { - const blacklistedPatternsFilename = 'exclusions.txt'; let blacklistedPatterns = null; @@ -18,13 +17,17 @@ const playwrightAxeGenerator = async (domain, data) => { let unsafe = blacklistedPatterns.filter(function (pattern) { return !safe(pattern); }); - - if (unsafe.length > 0 ) { - let unsafeExpressionsError = "Unsafe expressions detected: '"+ unsafe +"' Please revise " + blacklistedPatternsFilename; + + if (unsafe.length > 0) { + let unsafeExpressionsError = + "Unsafe expressions detected: '" + + unsafe + + "' Please revise " + + blacklistedPatternsFilename; consoleLogger.error(unsafeExpressionsError); silentLogger.error(unsafeExpressionsError); process.exit(1); - }; + } } let { isHeadless, randomToken, deviceChosen, customDevice, viewportWidth } = data; @@ -247,7 +250,15 @@ const processPage = async page => { await createDetailsAndLogs(scanDetails, '${randomToken}'); await createAndUpdateResultsFolders('${randomToken}'); createScreenshotsFolder('${randomToken}'); - await generateArtifacts('${randomToken}', '${domain}', 'Customized', '${viewportWidth ? `CustomWidth_${viewportWidth}px` : customDevice ? customDevice : deviceChosen ? deviceChosen : 'Desktop' }'); + await generateArtifacts('${randomToken}', '${domain}', 'Customized', '${ + viewportWidth + ? `CustomWidth_${viewportWidth}px` + : customDevice + ? customDevice + : deviceChosen + ? deviceChosen + : 'Desktop' + }'); });`; let tmpDir; @@ -259,20 +270,25 @@ const processPage = async page => { const generatedScript = `./custom_flow_scripts/generatedScript-${randomToken}.js`; - console.log(` ℹ️ A new browser will be launched shortly.\n Navigate and record custom steps for ${domain} in the new browser.\n Close the browser when you are done recording your steps.`); + console.log( + ` ℹ️ A new browser will be launched shortly.\n Navigate and record custom steps for ${domain} in the new browser.\n Close the browser when you are done recording your steps.`, + ); try { tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), appPrefix)); - let browser = "webkit"; + let browser = 'webkit'; let userAgentOpts = null; - + // Performance workaround for macOS Big Sur and Windows to force Chromium browser instead of Webkit - if ((os.platform() ==='darwin' && os.release().startsWith("20.")) || os.platform() ==='win32' ) { - browser = "chromium"; + if ( + (os.platform() === 'darwin' && os.release().startsWith('20.')) || + os.platform() === 'win32' + ) { + browser = 'chromium'; if (deviceChosen === 'Mobile') { - customDevice = "iPhone 11"; + customDevice = 'iPhone 11'; } if (customDevice) { @@ -304,9 +320,7 @@ const processPage = async page => { } if (codegenResult.toString()) { - console.error( - `Error running Codegen: ${codegenResult.toString()}`, - ); + console.error(`Error running Codegen: ${codegenResult.toString()}`); } const fileStream = fs.createReadStream(`${tmpDir}/intermediateScript.js`); @@ -373,7 +387,7 @@ const processPage = async page => { continue; } - let pageObj = "page"; + let pageObj = 'page'; if (line.trim().startsWith(`await page`)) { const regexPageObj = /(?<=await )(.*?)(?=\.)/; @@ -386,8 +400,8 @@ const processPage = async page => { appendToGeneratedScript( `${line} await processPage(page); - ` - ,); + `, + ); continue; } else { const regexURL = /(?<=goto\(\')(.*?)(?=\'\))/; @@ -400,11 +414,9 @@ const processPage = async page => { appendToGeneratedScript(` await ${pageObj}.waitForURL('${lastGoToUrl}**',{timeout: 60000}); await processPage(page); - `, - ); + `); lastGoToUrl = null; - } else if (nextStepNeedsProcessPage) { appendToGeneratedScript(`await processPage(page);`); nextStepNeedsProcessPage = false; @@ -424,7 +436,7 @@ const processPage = async page => { } else { nextStepNeedsProcessPage = false; } - + if (line.trim() === `await browser.close();`) { appendToGeneratedScript(line); appendToGeneratedScript(block2); @@ -437,7 +449,6 @@ const processPage = async page => { console.log(` Browser closed. Replaying steps and running accessibility scan...\n`); await import(generatedScript); - } catch (e) { console.error(`Error: ${e}`); throw e; @@ -453,9 +464,7 @@ const processPage = async page => { } console.log(`\n You may re-run the recorded steps by executing:\n\tnode ${generatedScript} \n`); - } - }; export default playwrightAxeGenerator; diff --git a/static/ejs/partials/components/ruleOffcanvas.ejs b/static/ejs/partials/components/ruleOffcanvas.ejs index ce66d08b..b87431aa 100644 --- a/static/ejs/partials/components/ruleOffcanvas.ejs +++ b/static/ejs/partials/components/ruleOffcanvas.ejs @@ -15,11 +15,17 @@ aria-label="Close" > -

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. -

+ + Learn more about this issue

Conformance:

diff --git a/static/ejs/partials/components/scanAbout.ejs b/static/ejs/partials/components/scanAbout.ejs index c4159e85..30dc913a 100644 --- a/static/ejs/partials/components/scanAbout.ejs +++ b/static/ejs/partials/components/scanAbout.ejs @@ -34,7 +34,7 @@ fill="#CED4DA" /> - <%= urlScanned %> + <%= urlScanned %>
<% if (viewport.startsWith('Desktop')) { %> @@ -140,11 +140,15 @@

+ diff --git a/static/ejs/partials/header.ejs b/static/ejs/partials/header.ejs index cf3a03a0..e3ac2eb7 100644 --- a/static/ejs/partials/header.ejs +++ b/static/ejs/partials/header.ejs @@ -1,23 +1,54 @@ diff --git a/static/ejs/partials/main.ejs b/static/ejs/partials/main.ejs index 1fd5ef1b..f8778ef3 100644 --- a/static/ejs/partials/main.ejs +++ b/static/ejs/partials/main.ejs @@ -16,7 +16,6 @@
<%# dynamically generated section from scripts/categorySummary %>
- <%- include("components/ruleOffcanvas") %> - <%- include("footer") %> + <%- include("components/ruleOffcanvas") %> <%- include("footer") %> diff --git a/static/ejs/partials/scripts/categorySummary.ejs b/static/ejs/partials/scripts/categorySummary.ejs index 4a5a1b2a..1a0e2f2e 100644 --- a/static/ejs/partials/scripts/categorySummary.ejs +++ b/static/ejs/partials/scripts/categorySummary.ejs @@ -50,4 +50,3 @@ document.getElementById('categorySummary').replaceChildren(...newItems); } - \ No newline at end of file diff --git a/static/ejs/partials/scripts/ruleOffcanvas.ejs b/static/ejs/partials/scripts/ruleOffcanvas.ejs index fb9b3d72..69d92ac4 100644 --- a/static/ejs/partials/scripts/ruleOffcanvas.ejs +++ b/static/ejs/partials/scripts/ruleOffcanvas.ejs @@ -67,6 +67,34 @@ category summary is clicked %> `), ); + let expandedRuleDescription = document.getElementById('expandedRuleDescription'); + let expandedRuleCollapseButton = document.getElementById('expandedRuleCollapseButton'); + + if (expandedRuleDescription.classList.contains('show')) { + expandedRuleDescription.classList.remove('show'); + } + + if (expandedRuleDescription.ariaExpanded === 'true') { + expandedRuleDescription.ariaExpanded = 'false'; + } + + if (expandedRuleCollapseButton.classList.contains('collapsed') !== true) { + expandedRuleCollapseButton.classList.add('collapsed'); + } + + expandedRuleDescription.style.minHeight = ''; + + if (expandedRuleDescription.offsetHeight === expandedRuleDescription.scrollHeight) { + expandedRuleCollapseButton.style.display = 'none'; + expandedRuleDescription.ariaExpanded = 'true'; + } else { + expandedRuleDescription.classList.add('collapse'); + + expandedRuleCollapseButton.style.display = 'block'; + expandedRuleDescription.ariaExpanded = 'false'; + expandedRuleDescription.style.minHeight = '3rem'; // Prevents bootstrap collapse from going to 0px + } + const availableFixCategories = []; const categorySelectors = []; diff --git a/static/ejs/partials/styles/styles.ejs b/static/ejs/partials/styles/styles.ejs index 12b68102..fba357f5 100644 --- a/static/ejs/partials/styles/styles.ejs +++ b/static/ejs/partials/styles/styles.ejs @@ -35,7 +35,18 @@ border-color: #b5c5ca; opacity: 1; } - h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { + h6, + .h6, + h5, + .h5, + h4, + .h4, + h3, + .h3, + h2, + .h2, + h1, + .h1 { color: unset; } #accessibility-site-report h1 { @@ -473,9 +484,55 @@ font-weight: bold; line-height: 2rem; } + #expandedRuleDescription { + position: relative; + } + + #expandedRuleDescription.collapse::after { + content: ''; + position: absolute; + z-index: 1; + bottom: 0; + left: 0; + pointer-events: none; + background-image: linear-gradient( + to bottom, + rgba(255, 255, 255, 0), + rgba(255, 255, 255, 1) 80% + ); + width: 100%; + height: 1rem; + } + + #expandedRuleDescription.collapse.show::after { + content: none; + } + + #expandedRuleDescription.collapse:not(.show) { margin-top: 2rem; + overflow: hidden; + display: block; + max-height: 3rem; + } + + #expandedRuleCollapseButton { + margin-top: 0.5rem; + margin-bottom: 1.5rem; + border: 0; + background: none; + color: #0047fa; + padding: 0; + } + + #expandedRuleCollapseButton.collapsed::after { + content: 'Read More'; } + + #expandedRuleCollapseButton:not(.collapsed)::after { + content: 'Show Less'; + } + #expandedRuleHelpUrl { display: block; margin-bottom: 1rem;