Skip to content

Commit d739c60

Browse files
authored
Use local http server (#64)
* Initialise & use local http server * Strip local url in reporter * Update snapshots * Use constants to configure server * Clean up server file * Re-enable CSP * Contain server functionality to server.js file * Add explainer comments * Fix reporter output * Update snapshots * Rewrite server module * publicDir --> publishDir * Minor cleanup * Add in-prigress message before runPa11y * Prepend server address in map callback * Update snapshots * Remove extraneous server method * Import mime types from json file * Allow ts to process json files * Update lockfike
1 parent 93e7991 commit d739c60

File tree

9 files changed

+504
-471
lines changed

9 files changed

+504
-471
lines changed

package-lock.json

Lines changed: 405 additions & 454 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/config.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,8 @@ const getConfiguration = ({
2323
}
2424

2525
const getPa11yOpts = async (wcagLevel) => {
26-
const browser = await puppeteer.launch({
27-
// NB: Allows iframes to load when HTML page is visited from filesystem.
28-
// Without this, a page with an iframe will crash pa11y
29-
args: ['--disable-web-security'],
30-
ignoreHTTPSErrors: true,
31-
})
32-
3326
return {
34-
browser,
27+
browser: await puppeteer.launch({ ignoreHTTPSErrors: true }),
3528
runners: PA11Y_RUNNERS,
3629
userAgent: PA11Y_USER_AGENT,
3730
standard: wcagLevel || PA11Y_DEFAULT_WCAG_LEVEL,

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ module.exports = {
1717
fileAndDirPaths: checkPaths,
1818
})
1919

20+
console.log('Checking your pages. This may take a while...')
21+
2022
const { report, issueCount } = await runPa11y({
2123
build,
2224
htmlFilePaths,
25+
publishDir,
2326
wcagLevel,
2427
})
2528
const reportSummary =

src/mimeTypes.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
".html":"text/html",
3+
".js":"text/javascript",
4+
".mjs":"text/javascript",
5+
".json":"application/json",
6+
".css":"text/css",
7+
".ico":"image/x-icon",
8+
".gif":"image/gif",
9+
".png":"image/png",
10+
".jpg":"image/jpeg",
11+
".jpeg":"image/jpeg",
12+
".webp":"image/webp",
13+
".bmp":"image/bmp",
14+
".svg":"image/svg+xml",
15+
".wav":"audio/wav",
16+
".mp3":"audio/mpeg",
17+
".mp4":"video/mpeg",
18+
".weba":"audio/wav",
19+
".webm":"video/wav",
20+
".pdf":"application/pdf",
21+
".otf":"font/otf",
22+
".woff":"font/woff",
23+
".ttf":"font/ttf",
24+
".woff2":"font/woff2"
25+
}

src/pluginCore.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@ const { isDirectory, isFile } = require('path-type')
66
const { results: cliReporter } = require('./reporter')
77
const readdirp = require('readdirp')
88
const { getPa11yOpts } = require('./config')
9+
const { StaticServer, SERVER_ADDRESS } = require('./server')
910

1011
const EMPTY_ARRAY = []
1112
const ASTERISK = '*'
1213
const HTML_EXT = '.html'
1314
const GLOB_HTML = '*.html'
1415

15-
exports.runPa11y = async function ({ build, htmlFilePaths, wcagLevel }) {
16+
exports.runPa11y = async function ({ build, htmlFilePaths, publishDir, wcagLevel }) {
1617
const pa11yOpts = await getPa11yOpts(wcagLevel)
1718
let issueCount = 0
1819

20+
const staticServer = new StaticServer(publishDir).listen()
21+
1922
const results = await Promise.all(
20-
htmlFilePaths.map(async (path) => {
23+
htmlFilePaths.map(async (/** @type {string} */ filePath) => {
2124
try {
22-
const res = await pa11y(path, pa11yOpts)
25+
const res = await pa11y(join(SERVER_ADDRESS, filePath), pa11yOpts)
2326
if (res.issues.length) {
2427
issueCount += res.issues.length
2528
return cliReporter(res)
@@ -30,6 +33,8 @@ exports.runPa11y = async function ({ build, htmlFilePaths, wcagLevel }) {
3033
}),
3134
)
3235

36+
staticServer.close()
37+
3338
await pa11yOpts.browser.close()
3439

3540
return {

src/reporter.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
'use strict'
1010

11-
const { cyan, green, gray, red, underline, yellow } = require('picocolors')
11+
const { bold, cyan, green, gray, red, underline, yellow } = require('picocolors')
1212

1313
// Pa11y version support
1414
const PA11Y_SUPPORTS = '^6.0.0 || ^6.0.0-alpha || ^6.0.0-beta'
@@ -17,7 +17,7 @@ const DUPLICATE_WHITESPACE_EXP = /\s+/g
1717
const EMPTY_SPACE = ' '
1818
const NEWLINE_LITERAL = '\n'
1919

20-
const rootFilePath = 'file://' + process.cwd()
20+
const LOCAL_FILE_PATH_EXP = new RegExp(`^http://localhost:\\d{4}/|${'file://' + process.cwd()}/`);
2121

2222
// Helper strings for use in reporter methods
2323
const start = cyan(' >')
@@ -44,8 +44,8 @@ function renderIssue(issue) {
4444

4545
// Output formatted results
4646
function renderResults(results) {
47-
const relativeFilePath = results.pageUrl.replace(rootFilePath, '.')
4847
if (results.issues.length) {
48+
const publicFilePath = results.pageUrl.replace(LOCAL_FILE_PATH_EXP, '')
4949
const totals = {
5050
error: 0,
5151
notice: 0,
@@ -71,7 +71,7 @@ function renderResults(results) {
7171

7272
return cleanWhitespace(`
7373
74-
${underline(`Results for file: ${relativeFilePath}`)}
74+
${bold(`Results for file ${underline(publicFilePath)}:`)}
7575
${issues.join(NEWLINE_LITERAL)}
7676
7777
${summary.join(NEWLINE_LITERAL)}

src/server.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// @ts-check
2+
const http = require('http')
3+
const fs = require('fs')
4+
const path = require('path')
5+
const MIME_TYPES = require('./mimeTypes.json')
6+
7+
const HTML_EXT = '.html'
8+
9+
const SERVER_HOST = 'localhost'
10+
const SERVER_PORT = '9000'
11+
const SERVER_ADDRESS = 'localhost:' + SERVER_PORT
12+
13+
const SERVER_OPTS = {
14+
host: SERVER_HOST,
15+
port: SERVER_PORT,
16+
}
17+
18+
const basePath = process.cwd()
19+
20+
class StaticServer {
21+
/**
22+
* @param {string} publishDir
23+
*/
24+
constructor(publishDir) {
25+
this.instance = http.createServer(async function (req, res) {
26+
const ext = path.extname(req.url)
27+
const filepath = ext === HTML_EXT ? path.join(basePath, req.url) : path.join(basePath, publishDir, req.url)
28+
29+
res.writeHead(200, { 'Content-type': MIME_TYPES[ext] || 'text/plain' })
30+
const stream = fs.createReadStream(filepath, { encoding: 'utf-8' })
31+
32+
stream.on('open', function () {
33+
stream.pipe(res)
34+
})
35+
36+
stream.on('error', function (err) {
37+
res.statusCode = 500
38+
res.end(`Error getting the file: ${err}.`)
39+
})
40+
41+
res.on('close', function () {
42+
stream.destroy()
43+
})
44+
})
45+
}
46+
47+
listen() {
48+
return this.instance.listen(SERVER_OPTS)
49+
}
50+
}
51+
52+
module.exports = {
53+
StaticServer,
54+
SERVER_ADDRESS,
55+
}

tests/runPa11y/__snapshots__/this.test.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ exports[`runPa11y works 1`] = `
44
Object {
55
"issueCount": 1,
66
"report": "
7-
[4mResults for file: ./tests/runPa11y/publishDir/index.html[24m
7+
[1mResults for file [4mtests/runPa11y/publishDir/index.html[24m:[22m
88
99
Error: Images must have alternate text (https://dequeuniversity.com/rules/axe/4.3/image-alt?application=axeAPI)
1010
 ├── image-alt

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
"types": ["jest"],
99
"esModuleInterop": true,
1010
"removeComments": true,
11+
"resolveJsonModule": true,
1112
"skipLibCheck": true /* Skip type checking of declaration files. */,
1213
"forceConsistentCasingInFileNames": true
1314
},
1415
"include": ["src/**/*.ts", "src/**/*.js"]
15-
}
16+
}

0 commit comments

Comments
 (0)