利用 Chromatic + Storybook 來做 Component-Level 的 Visual Testing

安裝 Storybook 與 Chromatic

利用 Chromatic 來看 UI 變更與決定是否要 approve 這個變更

提交 PR,這裡看到一些檢查,主要有三個部份…

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 範例

在 Chromatic 服務上看到這次的 PR 需要被 review。

Chromatic 範例

點進去看細節…

若為更新而非新增,Chromatic 會標記相異的地方,包含程式碼和元件產出的畫面,讓我們一眼看出哪兒不同,接著就可以決定是否要 approve 這個變更。

Chromatic 範例

approve 後會看到通過。

Chromatic 範例

疑難雜症 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 在 320px1200px 之下的兩種狀況。

TestStory.parameters = {
  viewports: [320, 576, 768, 992]
};

Viewports for all components

在 Storybook 的 preview.js 設定 parameters。如下,設定檢測 320px1200px 兩種狀況。

export const parameters = {
  chromatic: {
    viewports: [320, 576, 768, 992]
  }
}

如下圖,針對不同 viewport 產生不同 snaphots。

如何針對不同的 viewport 的狀況?

320px、576px、768px、992px 共 4 種。

如何針對不同的 viewport 的狀況?

320px

如何針對不同的 viewport 的狀況?

576px

如何針對不同的 viewport 的狀況?

768px

如何針對不同的 viewport 的狀況?

992px

如何針對不同的 viewport 的狀況?

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 😂 不過到底要調多少,是需要跟團隊一同測試的。

export const parameters = {
  chromatic: {
    diffThreshold: 0.05
  }
}

將共用元件 <Text>margin-left 增加 1px

<Text ml="1px">

修改前如下圖。

threshold

修改後如下圖,差異很小很小,差別是所有的文字區塊都會往右移一點點,肉眼雖然可察覺,但對於大多數使用者來說,整體 UI 來說差異並不顯著。

threshold

Chromatic 幫我們做比對,標記綠線表示與前一版不同之處,由此可知差異真的很小。這時就可以考慮這樣的差異是否要被檢查出來,意即設定 threshold 來決定這樣的差異是否為 visual noise,若認為是 visual noise 就忽略而不作通知。

而下圖的 threshold 為 0,也就是任何的不同都會被標記出來。

threshold

threshold 改為 0.05 後,即可忽略掉上面提到的狀況,也就是判定這樣的差異不是我們想要檢查出來的。

threshold


除了 PR review 外,在 A/B Test 方面,若希望不同版本的內容差異或相似度管控在某個範圍內,就可以用 visual testing 來做檢測,可參考這篇文章

疑難雜症 5:如何整合到工作流程?

工作流程為 Submit PR -> CI/CD 跑測試 -> 產生截圖 -> 比對差異 -> Review -> Merge。

工作流程

圖片來源:Test - Chromatic docs

完整的工作流程可參考-The Delightful Storybook Workflow

小記

先前提到,如果測試的頁面有會變動的內容 (例如:廣告),整頁做 snapshot 來比對是一定會失敗的,因此建議做元件的 snapshot 比對;或說網頁本由元件堆疊而成,測元件是最基本的策略。也就是說,Chromatic + Storybook 提供了元件做 visual testing 的解法。


以上部份截圖來自 Mixtini,特別感謝 Sean Chou 出借 Mixtini 讓我做技術研究和實作 !


comments powered by Disqus