Puppeteerで使う
Puppeteerは、DevToolsプロトコル経由でヘッドレスまたは通常のChrome/Chromiumを操作するNode.jsライブラリーです。ブラウザーの自動化とスクリプト実行のためのもので、テストによく使われますが、それ自体はテストフレームワークではありません。surea11yは@surea11y/puppeteerバインディングで連携します。
$ npm install @surea11y/core @surea11y/puppeteer puppeteer
Puppeteerはnpm installの一部として専用のChromeをダウンロードします。Playwrightと違い、ブラウザーを別途インストールする手順はありません。
const puppeteer = require('puppeteer');const { A11yCoreBuilder } = require('@surea11y/puppeteer');const browser = await puppeteer.launch();const page = await browser.newPage();await page.goto('https://example.com/');const results = await new A11yCoreBuilder({ page }).include('#main') // optional -- call multiple times for multi-region scans.exclude('.cookie-banner') // optional.withWcag('2.2', 'AA') // the rules for WCAG 2.2's A and AA criteria.disableRules(['meta-refresh-no-exceptions']).analyze();console.log(results.checksResults.filter(r => r.outcome === 'fail'));await browser.close();
.withWcag(version, level)は適合性の目標で選択します。WCAG 2.2のレベルAとAAの達成基準のルールを、各達成基準がそのバージョンで持つレベルに従って実行します。.withBestPractices()は、WCAGの達成基準を検査しないregionなどのルールを追加します。単独で使うと、それらのルールだけを実行します。
.withPacks()はスキャンの前にページへパックを登録し、.options({ profile })でそのプロファイルを選びます。実行されなかったパックは'pack-skipped'のスキャンギャップとして報告されるため、getScanGaps(results)を検証するテストは、パックなしで合格せずに失敗します。
Webコンポーネント。ElementInternalsをプライベートフィールドに保持し、それを通じて名前や状態、ロールを自分に設定するコンポーネントは、ページのどのスクリプトからも読み取れません。そのため既定では、スキャンはそのようなコンポーネントを判定せずに確認を求め(cantTell)、その方法だけで設定されたロールはまったくチェックされません。コンポーネントライブラリーを作ったりテストしたりしているなら、ページ自身のスクリプトが実行される前に、バインディングのオプトインのinternalsフックをインストールしてください。そうすれば、それらのコンポーネントもほかのコントロールと同じように判定されます。
const page = await browser.newPage();await A11yCoreBuilder.installInternalsHook(page); // before gotoawait page.goto('https://example.com/');
page.goto()の前に呼び出してください。page.evaluateOnNewDocument()を通じて実行されるので、1回の呼び出しでページが存在する間のフレームとナビゲーションがすべてカバーされます。ChromeとFirefoxで動作します。ページ自身が開いた新しいタブには適用されません。
このフックはテストや監査の実行のためのものです。記録した内容をページのどのスクリプトからも読める場所に保持するため、オプトインになっています。フックがない場合、スキャンはそのようなコンポーネントについて確認を求めたときに、一度だけそのことを知らせます。詳しくはREADMEのinternalsフックの節を参照してください。
クリックハンドラーとライブリージョン。core 1.14から、オプトインのフックがさらに2つあります。多くのページはクリックハンドラーをスクリプトから追加しますが、後からそれを一覧にできるページのスクリプトはありません。そのため、スキャンはクリックリスナーを持つ<div role="button">がキーボードでは何もしないことを見抜けません。リスナーフックがあれば、そのようなボタンは失敗します(CLICK_HANDLER_NO_KEY_LISTENER)。ライブリージョンフックは、ページのライブリージョンに何が与えられたかを記録します。スキャンはテキストが入った状態で追加された、スクリーンリーダーが読み上げないことの多いステータスメッセージについて確認を求め、announcements()はページが読み上げ用に提供した内容を返します。これで、操作の結果がユーザーに伝えられたかをテストで確かめられます。internalsフックと同じように、ページ自身のスクリプトが実行される前にインストールしてください。
const page = await browser.newPage();await A11yCoreBuilder.installListenerHook(page); // before gotoawait A11yCoreBuilder.installLiveRegionHook(page);await page.goto('https://example.com/settings');await page.click('#save');const said = await A11yCoreBuilder.announcements(page);// [{ text: 'Saved', politeness: 'polite', ..., selector: '#status' }]
どちらもinternalsフックと同じように、page.goto()の前にpage.evaluateOnNewDocument()でインストールします。
internalsフックと同じく、どちらもテストや監査の実行のためのものです。記録した内容はページのどのスクリプトからも読めます。announcements()はページが読み上げ用に提供した内容で、スクリーンリーダーが実際に読み上げた内容ではありません。ライブリージョンフックがなければnullです。どちらかのフックがない場合、そのフックなら判断できた検出結果がフックなしで判定されたときにgetScanNotes()がそのことを示します。詳しくはREADMEのリスナーフックとライブリージョンフックの節を参照してください。
ダークモード、スマートフォンの幅、重大度によるゲート。.conditions([{ colorScheme: 'dark' }, { width: 320 }])は、ページをそのままの状態でスキャンしたあと、条件ごとにもう一度スキャンし、1つの結果を返します。ルールの判定結果はすべてのスキャンのうち最も悪いものになり、各検出結果にはそれが見つかった条件が示されます。条件ごとに完全なスキャンを行います。また、.frames(true)とはまだ組み合わせられません。Firefoxでは幅は使えますが、カラースキームにはDevToolsプロトコルが必要で、PuppeteerではChromeにしかないため、Firefoxでは.analyze()がスキャンの前に拒否されます。getGatingFailures(results, { failOnSeverity: 'serious' })は、その重大度以上で失敗したルールを返します。これにより、ほかの問題は報告し続けながら、まず重大な問題と致命的な問題でテストを止められます。formatFailures()も同じオプションを受け取ります。
傾きと確認手順のある問い。core 1.14から、cantTellの検出結果は理由とともにfailまたはpassのどちらかに傾くことがあり、人が答えるための手順であるhowToCheckを持ちます。formatFailures()は失敗の直後に不適合の可能性が高い問いを並べ、{ howToCheck: true }で手順も出力します。不適合の可能性が高いものでもテストを失敗させるには、coreのleaningFailures(results)をゲートに加えてください。
A11yCoreBuilderにはほかにも、実行するルールを変えずに報告する達成基準をWCAGのレベルまでに絞る.wcagLevel()、タグのルールに名前を挙げたルールを加えて実行する.includeMode('or')、スキャンが何をチェックするかを実行前に一覧にし、何も実行しない選択が問題のないスキャンに見えないようにする.plannedChecks()と.plannedCriteria()、スキャンギャップの警告を自分のログに送る.logger()、CSSを読むルールのために、ページ自身が読めない別オリジンのスタイルシートを.analyze()が取得しないようにする.fetchStyleSheets(false)、ページがどのようにスキャンされたかを示すgetScanNotes(results)があります。それぞれの説明はバインディングのREADMEにあります。
パッケージのリポジトリにある実行可能なサンプルも参照してください。
次のステップ:実行するルールを選ぶ、スキャンをCIに組み込む、結果のスキーマ全体を確認する。