Skip to content

Commit

Permalink
index.jsをモジュール化 #8
Browse files Browse the repository at this point in the history
  • Loading branch information
hideki-a committed Feb 18, 2021
1 parent 7dca332 commit c6dcc9c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 161 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
@@ -0,0 +1,15 @@
# http://editorconfig.org
root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.js]
indent_style = space
indent_size = 4
26 changes: 6 additions & 20 deletions bin/axe-runner.js
@@ -1,8 +1,8 @@
#!/usr/bin/env node
const fs = require('fs');
const { spawn } = require('child_process');
const { Command } = require('commander');
const program = new Command();
const runner = require('../lib/runner');

const dateText = (() => {
const dateObj = new Date();
Expand All @@ -20,7 +20,6 @@ program
.option('-c, --config <value>', 'Path to configuration file.')
.action((urlFile, options) => {
urlFile = urlFile ? urlFile : 'sitemap.xml';
const config = options.config ? options.config : '';

if (!fs.existsSync(process.cwd() + '/report')) {
fs.mkdirSync(process.cwd() + '/report');
Expand All @@ -30,24 +29,11 @@ program
const csvFile = fs.createWriteStream(csvFilePath);
const BOM = '\ufeff';
csvFile.write(BOM);
const runner = spawn(
'node',
[
__dirname + '/../index.js',
urlFile,
config,
]
);
runner.stdout.on('data', data => {
csvFile.write(data);
});
runner.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
runner.on('close', (code) => {
if (code !== 0) {
console.log(`child process exited with code ${code}`);
}
process.stdout.write = csvFile.write.bind(csvFile);

const runnerPromise = runner(urlFile, options);
runnerPromise.then(() => {
process.exit(0);
});
});

Expand Down
140 changes: 0 additions & 140 deletions index.js

This file was deleted.

152 changes: 152 additions & 0 deletions lib/runner.js
@@ -0,0 +1,152 @@
require('dotenv').config()
const fs = require('fs');
const deepExtend = require('deep-extend');
const parser = require('fast-xml-parser');
const puppeteer = require('puppeteer');
const AXE_SOURCE = require('axe-core').source;
const AXE_LOCALE_JA = require('axe-core/locales/ja.json');
const AxeReports = require('@hideki_a/axe-reports');
const { Console } = require('console');

// https://www.npmjs.com/package/sleep
function msleep(n) {
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n);
}

function sleep(n) {
msleep(n*1000);
}

function mergeConfig(options) {
const defaultUserConfigPath = process.cwd() + '/axe-runner.config.js';
const defaltConfig = {
config: {
locale: AXE_LOCALE_JA,
},
context: null,
options: {
resultTypes: ['violations', 'incomplete', 'inapplicable'],
},
};
let userConfig;
if (options.config) {
const userConfigPath = process.cwd() + '/' + options.config;
if (fs.existsSync(userConfigPath)) {
userConfig = require(userConfigPath);
}
} else if (fs.existsSync(defaultUserConfigPath)) {
userConfig = require(defaultUserConfigPath);
}
const execConfig = deepExtend(defaltConfig, userConfig);
return execConfig;
}

async function setupDevice(browser, execConfig) {
let device;
if (execConfig.device) {
if (typeof execConfig.device === 'string') {
device = puppeteer.devices[execConfig.device];
} else if (typeof execConfig.device === 'object') {
device = execConfig.device;
}
}

if (!device) {
const userAgentString = await browser.userAgent();
device = {
name: 'Chrome',
userAgent: userAgentString,
viewport: {
width: 1280,
height: 800,
deviceScaleFactor: 1,
isMobile: false,
hasTouch: false,
isLandscape: false
}
};
}

return device;
}

function runner(urlFile, options) {
return new Promise(async (resolve) => {
const browser = await puppeteer.launch();
const execConfig = mergeConfig(options);
const device = await setupDevice(browser, execConfig);

// アクセシビリティテスト開始
AxeReports.createCsvReportHeaderRow();

const isXML = /\.xml$/.test(urlFile) ? true : false;
let urls;
if (isXML) {
const sitemap = fs.readFileSync(urlFile, { encoding: "utf-8" });
const sitemapJSON = parser.parse(sitemap);
urls = sitemapJSON.urlset.url;
} else {
urls = fs.readFileSync(urlFile, { encoding: "utf-8" });
urls = urls.replace(/\r\n?/g, '\n');
urls = urls.split('\n');
}

for (let i = 0, nUrls = urls.length; i < nUrls; i += 1) {
const url = isXML ? urls[i]['loc'] : urls[i];
if (!url) {
continue;
}

const page = await browser.newPage();
await page.setBypassCSP(true);
page.on('response', response => {
if (response.url() === url) {
if (response.status() === 401) {
console.error('HTTP 401 Unauthorized -', response.url());
} else if (response.status() === 404) {
console.error('HTTP 404 Not Found -', response.url());
}
}
});

// リクエスト間で少し間を取る
if (i !== 0) {
sleep(3);
}

// ページ読み込み
if (process.env.BASIC_AUTH_USERNAME && process.env.BASIC_AUTH_PASSWORD) {
await page.authenticate({
username: process.env.BASIC_AUTH_USERNAME,
password: process.env.BASIC_AUTH_PASSWORD
});
}
await page.emulate(device);
await page.goto(`${url}`);

// axeを注入して実行
// See also: https://www.mitsue.co.jp/knowledge/blog/a11y/201903/07_1700.html
await page.evaluate(`eval(${JSON.stringify(AXE_SOURCE)});`);
const results = await page.evaluate(
(config, context, options = {}) => {
const { axe } = window;
axe.configure(config);
return axe.run(context || document, options);
},
execConfig.config,
execConfig.context,
execConfig.options,
);

// 結果を確認
if (results.violations || results.incomplete || results.inapplicable) {
AxeReports.createCsvReportRow(results);
}
}

await browser.close();
resolve();
});
}

module.exports = runner;
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -18,7 +18,7 @@
"csv"
],
"license": "MIT",
"main": "index.js",
"main": "lib/runner.js",
"dependencies": {
"@hideki_a/axe-reports": "^1.1.11",
"axe-core": "^4.1.0",
Expand Down

0 comments on commit c6dcc9c

Please sign in to comment.