無障礙測試
觀看影片教學
無障礙性是指讓網站對所有人都能存取的實踐。這意味著支援以下要求:鍵盤導覽、螢幕閱讀器支援、觸控友善、可用的色彩對比、減少動態效果和縮放支援。
無障礙測試會根據 WCAG 規則和其他業界認可的最佳實務,稽核渲染的 DOM 是否符合一組啟發式規則。它們是第一道 QA 防線,用於發現明顯的無障礙違規行為。
使用 a11y 附加元件進行無障礙檢查
Storybook 提供官方的 a11y 附加元件。由 Deque 的 axe-core 提供技術支援,可自動偵測高達 57% 的 WCAG 問題。
設定 a11y 附加元件
如果您想使用 附加元件檢查 story 的無障礙性,則需要將其新增至 Storybook。您可以執行下列命令來完成此操作
npx storybook add @storybook/addon-a11y
啟動 Storybook,您會在 UI 中看到一些明顯的差異。新的工具列圖示和無障礙面板,您可以在其中檢查測試結果。
運作方式
Storybook 的 a11y 附加元件會在選取的 story 上執行 Axe。讓您可以在開發期間偵測並修正無障礙性問題。例如,如果您正在開發按鈕元件,並且包含以下一組 story
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
};
export default meta;
type Story = StoryObj<typeof Button>;
// This is an accessible story
export const Accessible: Story = {
args: {
primary: false,
label: 'Button',
},
};
// This is not
export const Inaccessible: Story = {
args: {
...Accessible.args,
backgroundColor: 'red',
},
};
在兩個 story 中循環瀏覽時,您會看到 Inaccessible
story 包含一些需要修正的問題。開啟無障礙面板中的違規標籤,可以清楚描述無障礙性問題和解決問題的指南。
設定
Storybook 的無障礙附加元件包含一組涵蓋大多數問題的無障礙規則。您也可以微調 附加元件設定或覆寫 Axe 的規則集,以最符合您的需求。
全域 a11y 設定
如果您需要忽略無障礙規則或修改其在所有 story 中的設定,您可以將以下內容新增至您的 storybook/preview.js|ts
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { Preview } from '@storybook/your-framework';
const preview: Preview = {
parameters: {
a11y: {
// Optional selector to inspect
element: '#storybook-root',
config: {
rules: [
{
// The autocomplete rule will not run based on the CSS selector provided
id: 'autocomplete-valid',
selector: '*:not([autocomplete="nope"])',
},
{
// Setting the enabled option to false will disable checks for this particular rule on all stories.
id: 'image-alt',
enabled: false,
},
],
},
// Axe's options parameter
options: {},
// Optional flag to prevent the automatic check
manual: true,
},
},
};
export default preview;
元件層級的無障礙設定
您還可以為元件的所有 stories 自訂一組規則。更新您 story 的預設匯出,並加入一個帶有所需設定的參數。
// Replace your-framework with the name of your framework
import type { Meta } from '@storybook/your-framework';
import { MyComponent } from './MyComponent';
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
parameters: {
a11y: {
// Optional selector to inspect
element: '#storybook-root',
config: {
rules: [
{
// The autocomplete rule will not run based on the CSS selector provided
id: 'autocomplete-valid',
selector: '*:not([autocomplete="nope"])',
},
{
// Setting the enabled option to false will disable checks for this particular rule on all stories.
id: 'image-alt',
enabled: false,
},
],
},
options: {},
manual: true,
},
},
};
export default meta;
Story 層級的無障礙設定
透過更新您的 story 以包含新的參數,來自訂 story 層級的 a11y 規則集。
import type { Meta, StoryObj } from '@storybook/react';
import { MyComponent } from './MyComponent';
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const ExampleStory: Story = {
parameters: {
a11y: {
element: '#storybook-root',
config: {
rules: [
{
// The autocomplete rule will not run based on the CSS selector provided
id: 'autocomplete-valid',
selector: '*:not([autocomplete="nope"])',
},
{
// Setting the enabled option to false will disable checks for this particular rule on all stories.
id: 'image-alt',
enabled: false,
},
],
},
options: {},
manual: true,
},
},
};
如何停用 a11y 測試
透過將以下參數分別加入至您 story 的匯出或元件的預設匯出,來停用 stories 或元件的無障礙測試。
import type { Meta, StoryObj } from '@storybook/react';
import { MyComponent } from './MyComponent';
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const NonA11yStory: Story = {
parameters: {
a11y: {
// This option disables all a11y checks on this story
disable: true,
},
},
};
使用測試執行器自動執行無障礙測試
檢查無障礙功能最準確的方式是在真實裝置上手動檢查。不過,您可以使用自動化工具來找出常見的無障礙問題。例如,Axe 平均可以自動找出高達 57% 的 WCAG 問題。
這些工具會根據 WCAG 規則和其他業界接受的最佳實務,審核已渲染的 DOM 並使用啟發式方法。然後,您可以使用 Storybook 測試執行器和 axe-playwright 將這些工具整合到您的測試自動化流程中。
設定
若要使用測試執行器啟用無障礙測試,您需要採取額外的步驟進行正確的設定。我們建議您在繼續進行其餘的必要設定之前,先瀏覽 測試執行器文件。
執行以下命令以安裝所需的相依性。
npm install axe-playwright --save-dev
在您的 Storybook 目錄內新增一個 設定檔,並在其中加入以下內容
import type { TestRunnerConfig } from '@storybook/test-runner';
import { injectAxe, checkA11y } from 'axe-playwright';
/*
* See https://storybook.dev.org.tw/docs/writing-tests/test-runner#test-hook-api
* to learn more about the test-runner hooks API.
*/
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page) {
await checkA11y(page, '#storybook-root', {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;
preVisit
和 postVisit
是方便的 hook,可讓您擴充測試執行器的預設設定。請在此處閱讀更多相關資訊 這裡。
當您執行測試執行器時 (例如,使用 yarn test-storybook
),它會執行無障礙審核以及您可能已為每個元件 story 設定的任何元件測試。
它會從 story 的根元素開始遍歷 DOM 樹狀結構,並根據它遇到的問題產生詳細的報告,藉此開始檢查問題。
使用測試執行器的 A11y 設定
測試執行器提供輔助方法,允許存取 story 的資訊。您可以使用它們來擴充測試執行器的設定,並提供您可能對特定 story 擁有的其他選項。例如
import type { TestRunnerConfig } from '@storybook/test-runner';
import { getStoryContext } from '@storybook/test-runner';
import { injectAxe, checkA11y, configureAxe } from 'axe-playwright';
/*
* See https://storybook.dev.org.tw/docs/writing-tests/test-runner#test-hook-api
* to learn more about the test-runner hooks API.
*/
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page, context) {
// Get the entire context of a story, including parameters, args, argTypes, etc.
const storyContext = await getStoryContext(page, context);
// Apply story-level a11y rules
await configureAxe(page, {
rules: storyContext.parameters?.a11y?.config?.rules,
});
const element = storyContext.parameters?.a11y?.element ?? '#storybook-root';
await checkA11y(page, element, {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;
使用測試執行器停用 a11y 測試
此外,如果您已為任何特定的 story 停用無障礙測試,您也可以設定測試執行器以避免測試該 story。例如
import type { TestRunnerConfig } from '@storybook/test-runner';
import { getStoryContext } from '@storybook/test-runner';
import { injectAxe, checkA11y } from 'axe-playwright';
/*
* See https://storybook.dev.org.tw/docs/writing-tests/test-runner#test-hook-api
* to learn more about the test-runner hooks API.
*/
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page, context) {
// Get the entire context of a story, including parameters, args, argTypes, etc.
const storyContext = await getStoryContext(page, context);
// Do not run a11y tests on disabled stories.
if (storyContext.parameters?.a11y?.disable) {
return;
}
await checkA11y(page, '#storybook-root', {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;
基於瀏覽器的無障礙測試和基於 linter 的無障礙測試有什麼區別?
基於瀏覽器的無障礙測試 (例如 Storybook 中的測試) 會評估已渲染的 DOM,因為這可提供最高的準確性。審核尚未編譯的程式碼與真實情況相差一步,因此您無法捕捉到使用者可能會體驗到的所有情況。
了解其他 UI 測試