This article was translated from Japanese by AI and may contain inaccuracies. For the most accurate content, please refer to the original Japanese version.
accesibility

Pa11y CI でアクセシビリティテストを GitHub Actions で実行する

Pa11y とは Web Content Accessibility Guidelines (WCAG) をベースに HTML のアクセシビリティを検査するツールです。適合レベル AA を対象にテストします。Pa11y にはいくつかの種類がありますが、その中でも Pa11y CI は CI 上で実行することにフォーカスしています。

Pa11y とは Web Content Accessibility Guidelines (WCAG) をベースに HTML のアクセシビリティを検査するツールです。適合レベル AA を対象にテストします。Pa11y にはいくつかの種類がありますが、その中でも Pa11y CI は CI 上で実行することにフォーカスしています。

基本的な使い方

まずは Pa11y をインストールして使ってみましょう。前提条件として Node.js v12 以降が必要です。

npm install -g pa11y-ci

インストールが完了したら pa11y-ci コマンドが使えるようになります。アクセシビリティテストを実行したい URL を引数にコマンドを実行します。

pa11y-ci https://pa11y.org/
Running Pa11y on 1 URLs:
 > https://pa11y.org/ - 0 errors
 
 1/1 URLs passed

アクセシビリティ上問題がある箇所が発見された場合、以下のようなエラーが報告されます。

pa11y-ci http://localhost:3000/blog/markdown-test
Running Pa11y on 1 URLs:
 > http://localhost:3000/blog/markdown-test - 27 errors
 
Errors in http://localhost:3000/blog/markdown-test:
 
 This checkboxinput element does not have a name available to an accessibility API. Valid names are: label element, title
   undefined, aria-label undefined, aria-labelledby undefined.
 
   (#contents > ul:nth-child(39) > li:nth-child(1) > input)
 
   <input type="checkbox" disabled="">
 
 0/1 URLs passed

設定ファイルを利用する

デフォルトでは pa11y-ci を実行する際に現在の作業ディレクトリに .pa11yci または .pa11yci.json ファイルが存在する場合そのファイルの設定が使用されます。設定ファイルは JSON 形式で記載します。例えば、以下のようにテストしたい URL を配列で指定できます。

.pa11yci.json
{
  "urls": [
    "http://localhost:3000",
    "http://localhost:3000/blog",
    "http://localhost:3000/about",
    "http://localhost:3000/tags",
    "http://localhost:3000/blog/markdown-test"
  ]
}

すべての設定は以下から確認できます。

特定のルールを無視する

pa11y-ci を実行する際に特定のエラーの報告を無視したいこともあるでしょう。例えば、http://localhost:3000/blog/markdown-test という URL はマークダウンを HTML に変換してレンダリングしているので、ひとまずエラーが報告されても無視したいとします。

urls の配列の要素を文字列ではなくオブジェクトで指定すると、特定の URL に対してのみオプションを設定できます。特定のルールを無視するためには ignore の配列でルールのコードを指定します。

{
  "urls": [
    "http://localhost:3000",
    "http://localhost:3000/blog",
    "http://localhost:3000/about",
    "http://localhost:3000/tags",
    {
      "url": "http://localhost:3000/blog/markdown-test",
      "ignore": [
        "WCAG2AA.Principle2.Guideline2_4.2_4_1.H64.1",
        "WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.InputCheckbox.Name",
        "WCAG2AA.Principle1.Guideline1_3.1_3_1.F68",
        "WCAG2AA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr",
        "WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.A.EmptyNoId"
      ]
    }
  ]
}

ところで、ignore に指定するルールは https://squizlabs.github.io/HTML_CodeSniffer/Standards/WCAG2/ から探して指定するのですが、ターミナルの出力に対応するエラーをここから探すのは一苦労です。この場合には結果をターミナルに出力するのではなく、JSON 形式で出力すると細かい結果まで出力してくれます。

pa11y-ci --json > pa11y-ci-results.json

以下のように code と共にエラーを出力してくれます。

{
  "total": 5,
  "passes": 4,
  "errors": 27,
  "results": {
    "http://localhost:3000/": [],
    "http://localhost:3000/blog": [],
    "http://localhost:3000/about": [],
    "http://localhost:3000/tags": [],
    "http://localhost:3000/blog/markdown-test": [
      {
        "code": "WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.InputCheckbox.Name",
        "type": "error",
        "typeCode": 1,
        "message": "This checkboxinput element does not have a name available to an accessibility API. Valid names are: label element, title undefined, aria-label undefined, aria-labelledby undefined.",
        "context": "<input type=\"checkbox\" disabled=\"\">",
        "selector": "#contents > ul:nth-child(39) > li:nth-child(1) > input",
        "runner": "htmlcs",
        "runnerExtras": {}
      }
    ]
  }
}

テストの実行前にブラウザ操作を実行する

pa11y によるテストを実行する前にブラウザの操作を実行したい場合があるでしょう。例えば、ボタンをクリックしてダイアログを表示してからテストを実行するなどが考えられます。ブラウザ操作を実行する場合には actios の配列で指定します。click,input などのイベントを実行したり、wait for で特定の要素が出現するまで待機できます。要素を指定するためにのセレクタは document.querySelector で使用できるものと同等です。

下記の例ではダークモードに切り替えるボタンをクリックし、外見がダークモードに切り替えるのを待機してからアクセシビリティテストを実行しています。

{
  "urls": [
    "http://localhost:3000",
    {
      "url": "http://localhost:3000/",
      "actions": [
        "click button[aria-label='ダークモードに切り替える']",
        "wait for button[aria-label='ライトモードに切り替える'] to be visible"
      ]
    },
  ]
}

その他実行可能な actions は以下から確認できます。

GitHub Actions で実行する

ローカルで pa11y-ci の実行が確認できたので、それでは実際に CI 上で実行してみましょう。ここではコードを変更したときにアクセシビリティに違反していないかどうか PR で確認できるように GitHub Actions で実行する例を考えてみます。

ビルド → ローカルで起動 → pa11y-ci の流れで実行しています。npm run buildnpm run preview コマンドは各自のビルド、ローカル起動コマンドに置き換えてください。ローカルで起動が完了する前に pa11y-ci コマンドが実行されてしまうと失敗してしまうので、念のため sleep 3 で 3s 待機してから実行しています。

name: CI
on:
  pull_request:
 
jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: npm
      - name: Install dependencies
        run: npm ci && npm install -g pa11y-ci
      - name: Build
        run: npm run build
      - name: pa11y-ci
        run: npm run preview & sleep 3; pa11y-ci

参考