利用 Chromatic + Storybook 來做 Component-Level 的 Visual Testing
04 Mar 2022安裝 Storybook 與 Chromatic
- 步驟 1:安裝 Storybook 與撰寫 story、發佈 Storybook 。
- 步驟 2:安裝 Chromatic 與使用專案專用的 token 做執行,接著就會在 Chromatic 服務上看到元件的截圖。
利用 Chromatic 來看 UI 變更與決定是否要 approve 這個變更
提交 PR,這裡看到一些檢查,主要有三個部份…
- Chromatic:這是自己寫的 workflow,用於針對每個 PR 產出個別的 build 來做測試。
- Storybook Publish 和 UI Tests 是執行
chromaui/action@v1
做的檢查 (範例如下)。
name: 'Chromatic'
on: [pull_request]
jobs:
chromatic-deployment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install dependencies
run: yarn
- name: Publish to Chromatic
uses: chromaui/action@v1
with:
projectToken: $
GitHub 的 PR 上可以看到測試狀況與結果,如果是新增則需要 approve 作為 baseline。
在 Chromatic 服務上看到這次的 PR 需要被 review。
點進去看細節…
若為更新而非新增,Chromatic 會標記相異的地方,包含程式碼和元件產出的畫面,讓我們一眼看出哪兒不同,接著就可以決定是否要 approve 這個變更。
approve 後會看到通過。
疑難雜症 1:比對基準是什麼?
先提交一個 commit A,並且 accept 其中 4 個 snapshot。
推一個新的提交
Step 1: Already accept 4 snapshots as baseline for commit A.
Commits:
54ceb1b commit A
Step 2: Push a new commit.
再來,針對某個元件做修改,並推上去成為一個新的 commit B。
Commits:
54ceb1b commit A
96c01e1 commit B
從這裡可以看到,比較的基準變成 commit A 的 build 所 approve 的 snapshot。
推一個新的提交但重新定義分支的參考基準
但若在推 commit 前,先做 rebase 再推上去呢?
drop 剛才的 commit B,更新某個元件,並推上去成為一個新的 commit C。
Step 1: Already accept 4 accept snapshots as baseline for commit A.
Commits:
54ceb1b commit A
98hea3e commit C
將 commit C 做 rebase,fixup 到 commit A。
Step 2: Push a new commit and rebase it, i.e., fixup to the previous commit.
Commits:
27a4527 commit A
從這裡可以看到,若更新分支的參考基準 (亦即 rebase),後續推上來的 commit 還是是可以自 arpprove 的 snapshot 作為基準來比較的。
也就是說,rebase 對比較 snapshot 是沒有影響的,從官網可看到說明,Chromatic 追蹤的不是 git history,而是目前這個 branch 當中,各別 approve 的 story 的 snapshot 來比較。
更簡單的來說,一但這個 branch,accept 了某個 build 的 snapshot 作為 baseline 之後,這個 snaphot 就成為新的 baseline;之後不論此 branch 的 git history 或程式碼怎麼更新,Chromatic 都是拿這個新的 baseline 來做比較基準。
疑難雜症 2:有動畫的部分,只會截圖到部份內容?
原本在 Storybook 看到的畫面是這樣的。
打開 Chormatic 的 console。
發現某元件在動畫尚未 render 完畢就被 snapshot。
解決方法是針對這個 component 設定 delay 時間,待 render 完畢再做 snapshot。
TestStory.parameters = {
chromatic: { delay: 300 },
};
設定完就可以看到正常的截圖了!
疑難雜症 3:如何測試不同的 viewport 的狀況?
Viewports for a story
針對這個 component 設定要確認的 viewport。如下,設定檢測 TestStory 在 320px
與 1200px
之下的兩種狀況。
TestStory.parameters = {
viewports: [320, 576, 768, 992]
};
Viewports for all components
在 Storybook 的 preview.js
設定 parameters。如下,設定檢測 320px
與 1200px
兩種狀況。
export const parameters = {
chromatic: {
viewports: [320, 576, 768, 992]
}
}
如下圖,針對不同 viewport 產生不同 snaphots。
320px、576px、768px、992px 共 4 種。
320px
576px
768px
992px
Viewports for all pages (同場加映)
以下整合 end-to-end testing framework (在這裡以 Cypress 為例) + Percy。
在 .percy.json
做全域設定。
{
"version": 2,
"snapshot": {
"widths": [
320,
576,
768,
992
]
},
}
在單一測試範例可以這樣設定。
cy.percySnapshot('main page', { widths: [320, 576, 768, 992] });
疑難雜症 4:雜訊
不需要這麼敏銳的比對,怎麼辦?
有些微調的差異並不需要被檢查出來,為了避免頻繁通知,可設定 threshold 來略過 visual noise 😂 不過到底要調多少,是需要跟團隊一同測試的。
- Chromatic:可設定 0 ~ 1,預設值是
0.063
。 - Percy:提供五個區段 Strict、Recommended 和 Relaxed 可做選擇,不過這是要付費的,可參考這裡。
export const parameters = {
chromatic: {
diffThreshold: 0.05
}
}
將共用元件 <Text>
的 margin-left
增加 1px
。
<Text ml="1px">
修改前如下圖。
修改後如下圖,差異很小很小,差別是所有的文字區塊都會往右移一點點,肉眼雖然可察覺,但對於大多數使用者來說,整體 UI 來說差異並不顯著。
Chromatic 幫我們做比對,標記綠線表示與前一版不同之處,由此可知差異真的很小。這時就可以考慮這樣的差異是否要被檢查出來,意即設定 threshold 來決定這樣的差異是否為 visual noise,若認為是 visual noise 就忽略而不作通知。
而下圖的 threshold 為 0,也就是任何的不同都會被標記出來。
threshold 改為 0.05 後,即可忽略掉上面提到的狀況,也就是判定這樣的差異不是我們想要檢查出來的。
除了 PR review 外,在 A/B Test 方面,若希望不同版本的內容差異或相似度管控在某個範圍內,就可以用 visual testing 來做檢測,可參考這篇文章。
疑難雜症 5:如何整合到工作流程?
工作流程為 Submit PR -> CI/CD 跑測試 -> 產生截圖 -> 比對差異 -> Review -> Merge。
完整的工作流程可參考-The Delightful Storybook Workflow
小記
先前提到,如果測試的頁面有會變動的內容 (例如:廣告),整頁做 snapshot 來比對是一定會失敗的,因此建議做元件的 snapshot 比對;或說網頁本由元件堆疊而成,測元件是最基本的策略。也就是說,Chromatic + Storybook 提供了元件做 visual testing 的解法。