以前にaxe-coreを使ってアクセシビリティのテストツールを作成しましたが、WCAGでどの項目(ナンバリング)のどの適合レベルに違反しているかも合わせて見たかったので、ツールを改修してもう少し詳しく確認できるようにしてみます。
設定方法
基本的な設定方法については以前の記事をご確認ください。
今回確認したいWCAGのナンバリングや適合レベルはtagsの中に含まれているようなので、こちらの値を使います。
const puppeteer = require('puppeteer');
const { AxePuppeteer } = require('@axe-core/puppeteer');
const axeLocales = require('axe-core/locales/ja.json');
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
// テスト対象のURLリスト
const urls = [
'https://example.com/',
'https://example.com/about/',
];
// ルールの設定
const axeRules = [
'wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22a', 'wcag22aa', 'best-practice'
];
// CSVの設定
const csvWriter = createCsvWriter({
path: 'a11y-test_results.csv', // 出力されるCSVファイルのパス
header: [ // CSVのヘッダー情報
{ id: 'url', title: 'URL' }, // 対象のページURL
{ id: 'violationId', title: 'Violation ID' }, // 違反したルールのID
{ id: 'wcagNumber', title: 'WCAG Number' }, // WCAGでのナンバリング(またはBest practice)
{ id: 'level', title: 'Level' }, // WCAGでの適合レベル
{ id: 'impact', title: 'Impact' }, // 違反の影響度(critical, serious, moderate, minor)
{ id: 'html', title: 'HTML' }, // 違反箇所のHTML
{ id: 'target', title: 'Target' }, // 違反対象要素
{ id: 'description', title: 'Description' }, // エラー内容の説明
{ id: 'helpUrl', title: 'Help URL' }, // ルールに関する詳細なヘルプURL
]
});
// 対象のURLに対してアクセシビリティテストを実行
async function runAccessibilityTest(url) {
// ブラウザを起動して、新しい空白ページを開く
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
try {
// 指定したURLに移動
await page.goto(url, {
waitUntil: 'networkidle2' // ページが完全にロードされるまで待機
});
// axe-coreを使ってテストを実行
const results = await new AxePuppeteer(page)
.withTags(axeRules) // ルールの設定
.configure({
locale: axeLocales // 日本語ローカライズファイルを指定
})
.analyze();
// 違反結果を元に、CSVに出力するためのデータ形式に整形
const violations = results.violations.map(function(violation) {
// 各違反について、詳細なノード情報を取得して配列に追加
return violation.nodes.map(function(node) {
// 'wcagXXX'(wcag + 数字3桁)の正規表現
const wcagNumCheck = /^wcag\d{3}$/;
const wcagNumReplace = /^wcag(\d)(\d)(\d)$/;
// 'wcagXXXXX'(wcag + 数字2桁(2 or 21 or 22) + a or aa or aaa)の正規表現
const wcagLevelCheck = /^wcag\d{1,2}(a{1,3})$/;
const wcagLevelReplace = /^wcag(\d{1,2})(\d?)(a{1,3})$/;
let num = '';
let level = '';
for (let i = 0; i < violation.tags.length; i++) {
const val = violation.tags[i];
// ナンバリング
if(wcagNumCheck.test(val)) {
let comma = ', ';
if(num === '') comma = '';
num += val.replace(wcagNumReplace, (match, p1, p2, p3) => {
return `${comma}WCAG${p1}.${p2}.${p3}`;
});
// 適合レベル
} else if(wcagLevelCheck.test(val)) {
let comma = ', ';
if(level === '') comma = '';
level = val.replace(wcagLevelReplace, (match, p1, p2, p3) => {
const wcagPart = p2 ? `WCAG${p1}.${p2}` : `WCAG${p1}`;
const aPart = p3.toUpperCase();
return `${comma}${aPart}`;
});;
// best practice
} else if(val === 'best-practice') {
num += 'Best practice';
}
}
return {
url: url, // 対象のページURL
violationId: violation.id, // 違反したルールのID
wcagNumber: num,
level: level,
impact: violation.impact, // 違反の影響度(critical, serious, moderate, minor)
html: node.html, // 違反箇所のHTML
target: node.target, // 違反対象要素
description: violation.description, // エラー内容の説明
helpUrl: violation.helpUrl // ルールに関する詳細なヘルプURL
}
});
}).flat();
// 整形した違反データをCSVファイルに書き込み
await csvWriter.writeRecords(violations);
} catch (error) {
console.error(`Error testing ${url}:`, error);
} finally {
// ブラウザを閉じる
await browser.close();
}
}
// 全ての対象URLに対してテストを実行
(async () => {
for (const url of urls) {
await runAccessibilityTest(url);
}
console.log('テスト完了しました。');
})();
注意点として、ルールの項目を見る限りナンバリングは複数含まれることがあるようなので、その場合はカンマ区切りで出すようにしています。
コメントが承認されるまで時間がかかります。