返回UI 測試手冊
React
章節
  • 簡介
  • 視覺
  • 組件
  • 互動
  • 無障礙功能
  • 使用者流程
  • 自動化
  • 工作流程
  • 結論

使用 Storybook 進行無障礙功能測試

透過整合工具快速回饋

美國有 26% 的成年人至少有一種身心障礙。當您改善無障礙功能時,它對您目前和未來的客戶有著巨大的影響。這也是法律要求。

檢查無障礙功能最準確的方法是在真實裝置上手動檢查。但這需要專業知識和大量時間,而這兩者在前台團隊中都很稀缺。

這就是為什麼許多公司現在使用自動化和手動測試相結合的方式。自動化可以低成本地捕捉常見的無障礙功能問題。手動 QA 則保留給需要人工關注的棘手問題。

有很多資源深入探討了無障礙功能原則,因此我們在此不贅述。相反,我們將重點放在如何使用 Storybook 自動化無障礙功能測試。這是一種務實的方法,可以找到並修復您可能遇到的大多數問題。

為何要自動化?

在我們開始之前,先來檢視常見的身心障礙類型:視覺、聽覺、行動、認知、言語和神經系統。這些使用者身心障礙產生了應用程式需求,例如

  • ⌨ 鍵盤導航
  • 🗣 螢幕閱讀器支援
  • 👆 觸控友善
  • 🎨 足夠高的色彩對比
  • ⚡️ 減少動態效果
  • 🔍 縮放

過去,您需要透過檢查瀏覽器、裝置和螢幕閱讀器的組合中的每個組件來驗證這些需求。但是,手動執行此操作是不切實際的,因為應用程式有數十個組件,並且不斷更新 UI。

自動化加速您的工作流程

自動化工具根據 WCAG 規則和其他業界認可的最佳實務,稽核呈現的 DOM 是否符合一組啟發法規則。它們充當 QA 的第一道防線,以捕捉明顯的無障礙功能違規行為。

例如,Axe 平均能自動找出 57% 的 WCAG 問題。這讓團隊可以將其專家資源集中在需要人工審查的更複雜問題上。

許多團隊使用 Axe 函式庫,因為它與大多數現有的測試環境整合。例如,Twilio Paste 團隊使用 jest-axe 整合。而 Shopify Polaris 和 Adobe Spectrum 團隊則使用 Storybook 擴充套件 版本。

Storybook 擴充套件在瀏覽器中執行檢查(相對於 Jest 的 jsdom),因此可以捕捉到低對比度等問題。但是,它確實需要您手動驗證每個 Story。

無障礙功能測試工作流程

透過在整個開發過程中執行這些檢查,您可以縮短回饋迴圈並更快地修復問題。以下是工作流程的樣子

  1. 👨🏽‍💻 開發期間: 使用 Storybook 一次專注於一個組件。使用 A11y 擴充套件模擬視覺缺陷,並在組件層級執行無障礙功能稽核。
  2. 對於 QA: 將 Axe 稽核整合到您的功能測試管道中。對所有組件執行檢查以捕捉迴歸。

讓我們看看此工作流程的實際運作情況。

安裝無障礙功能擴充套件

Storybook 的無障礙功能在活動的 Story 上執行 Axe。它在面板中視覺化測試結果,並概述所有具有違規行為的 DOM 節點。

若要安裝擴充套件,請執行: yarn add --dev @storybook/addon-a11y。然後,將 '@storybook/addon-a11y' 新增至 .storybook/main.js 中的 addons 陣列

複製
.storybook/main.js
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
  staticDirs: ['../public'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
+   '@storybook/addon-a11y',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
};
export default config;

在編碼時測試無障礙功能

我們已經隔離了 Task 組件,並將其所有使用案例擷取為 Story。在開發階段,您可以循環瀏覽這些 Story 以找出無障礙功能問題。

複製
src/components/Task.stories.jsx
import Task from './Task';

export default {
  component: Task,
  title: 'Task',
  argTypes: {
    onArchiveTask: { action: 'onArchiveTask' },
    onTogglePinTask: { action: 'onTogglePinTask' },
    onEditTitle: { action: 'onEditTitle' },
  },
};

export const Default = {
  args: {
    task: {
      id: '1',
      title: 'Buy milk',
      state: 'TASK_INBOX',
    },
  },
};

export const Pinned = {
  args: {
    task: {
      id: '2',
      title: 'QA dropdown',
      state: 'TASK_PINNED',
    },
  },
};

export const Archived = {
  args: {
    task: {
      id: '3',
      title: 'Write schema for account menu',
      state: 'TASK_ARCHIVED',
    },
  },
};

const longTitleString = `This task's name is absurdly large. In fact, I think if I keep going I might end up with content overflow. What will happen? The star that represents a pinned task could have text overlapping. The text could cut-off abruptly when it reaches the star. I hope not!`;

export const LongTitle = {
  args: {
    task: {
      id: '4',
      title: longTitleString,
      state: 'TASK_INBOX',
    },
  },
};

請注意,擴充套件發現了兩個違規行為。第一個,「元素必須符合最低色彩對比度閾值」,特定於 archived 狀態。本質上,這表示任務標題與背景之間的對比度不足。我們可以透過在應用程式的 CSS(位於 src/index.css 中)中將文字顏色變更為較深的灰色來快速修復它。

複製
src/index.css
.list-item.TASK_ARCHIVED input[type="text"] {
- color: #a0aec0;
+ color: #4a5568;
  text-decoration: line-through;
}

第二個違規行為,「某些 ARIA 角色必須包含在特定的父元素中」,表示 DOM 結構不正確。Task 組件僅呈現 <li> 元素。因此,我們需要更新我們的 Story,將組件包裝在 <ul> 元素中。

複製
src/components/Task.stories.jsx
import Task from './Task';

export default {
  component: Task,
  title: 'Task',
  argTypes: {
    onArchiveTask: { action: 'onArchiveTask' },
    onTogglePinTask: { action: 'onTogglePinTask' },
    onEditTitle: { action: 'onEditTitle' },
  },
};

/*
*👇 Wraps the component with a custom render function.
* See https://storybook.dev.org.tw/docs/api/csf
* to learn how to use render functions.
*/
export const Default = {
  render: (args) => (
    <ul>
      <Task {...args} />
    </ul>
  ),
  args: {
    task: {
      id: '1',
      title: 'Buy milk',
      state: 'TASK_INBOX',
    },
  },
};

export const Pinned = {
  render: (args) => (
    <ul>
      <Task {...args} />
    </ul>
  ),
  args: {
    task: {
      id: '2',
      title: 'QA dropdown',
      state: 'TASK_PINNED',
    },
  },
};

export const Archived = {
  render: (args) => (
    <ul>
      <Task {...args} />
    </ul>
  ),
  args: {
    task: {
      id: '3',
      title: 'Write schema for account menu',
      state: 'TASK_ARCHIVED',
    },
  },
};

const longTitleString = `This task's name is absurdly large. In fact, I think if I keep going I might end up with content overflow. What will happen? The star that represents a pinned task could have text overlapping. The text could cut-off abruptly when it reaches the star. I hope not!`;

export const LongTitle = {
  render: (args) => (
    <ul>
      <Task {...args} />
    </ul>
  ),
  args: {
    task: {
      id: '4',
      title: longTitleString,
      state: 'TASK_INBOX',
    },
  },
};

您現在可以為所有其他組件重複此過程。

將無障礙功能測試整合到 Storybook 中簡化了您的開發工作流程。在處理組件時,您不必在不同的工具之間跳轉。您需要的一切都在瀏覽器中。您甚至可以模擬視覺障礙,例如二色性色盲、紅色盲或藍色盲。

使用測試執行器自動捕捉迴歸

通常,對組件的變更可能會意外引入新的無障礙功能問題。為了捕捉此類迴歸,您會在開啟提取請求之前測試所有 Story。但是,無障礙功能擴充套件僅在您檢視 Story 時執行檢查。若要一次測試所有 Story,我們可以使用 Storybook 測試執行器。它是一個獨立的實用程式(由 JestPlaywright 驅動),用於檢查 Story 中的呈現錯誤。

讓我們繼續設定測試執行器以執行 Axe。我們將從安裝 axe-playwright 開始。

複製
yarn add --dev axe-playwright

在您的 Storybook 目錄中新增一個新的組態檔,並在其中加入以下內容

複製
.storybook/test-runner.js
const { injectAxe, checkA11y } = require('axe-playwright');

module.exports = {
  async preVisit(page) {
    await injectAxe(page);
  },
  async postVisit(page) {
    await checkA11y(page, "#storybook-root", {
      detailedReport: true,
      detailedReportOptions: {
        html: true,
      },
    });
  },
};

preVisitpostVisit 是方便的鉤子,可讓您設定測試執行器以執行其他任務。我們正在使用這些鉤子將 Axe 注入到 Story 中,然後一旦它呈現,就執行無障礙功能測試。

您會注意到傳遞到 checkA11y 函式中的一些選項。我們已將 Axe 設定為從 Story 的根元素開始,然後遍歷 DOM 樹以檢查問題。它還將根據它遇到的問題產生詳細報告,並輸出違反無障礙功能規則的 HTML 元素清單。

若要執行測試,請在一個終端視窗中使用 yarn storybook 啟動 Storybook,並在另一個終端視窗中使用 yarn test-storybook 啟動測試執行器。

捕捉整合問題

UI 是透過組合組件並將它們連接到資料和 API 來組裝的。這有很多潛在的故障點。接下來,我們將研究如何使用 Cypress 透過一次性測試系統的所有層級來捕捉整合問題。

讓您的程式碼與本章保持同步。在 GitHub 上檢視 d16be74。
這個免費指南對您有幫助嗎?發推文表示讚賞,並幫助其他開發人員找到它。
下一章
使用者流程
驗證您的 UI 端對端運作
✍️ 在 GitHub 上編輯 – 歡迎 PR!
加入社群
6,721位開發人員及更多
為何選擇為何選擇 Storybook組件導向 UI
開放原始碼軟體
Storybook - Storybook 繁體中文

特別感謝 Netlify CircleCI