📑

@PreviewのついたComposableを使ってスクリーンショットテストする

2022/09/06に公開

対応内容はこちらのPRになります。
https://github.com/DroidKaigi/conference-app-2022/pull/97

元ネタはこちらになります。
https://github.com/android/nowinandroid/pull/101

元ネタと違いRepositoryに比較用の画像を配置しないでテストを実施するようにしました。

  • テストに使う画像はRepositoryに置かない
  • テストでDiffが出たらartifactに置く
  • DiffへのリンクをPRにコメントする(達成できず)

と言う仕様で対応をしました。

Kotlin系

作業内容としてはshowkaseとpaparazziを入れるくらいです。

Showcaseの設定

@PreviewのついたComposableがあるモジュールのBuild.gradleにkspとShowcaseの設定をします。
https://github.com/DroidKaigi/conference-app-2022/blob/19bef1610b1daeb42e58b7e88a0dd408d3fdf0d0/core-ui/build.gradle.kts

テスト用モジュールの作成

Build.gradle

preview-screenshotsと言うモジュール名で用意しました。

Paparazziを動かす場所です。
Build.gradleにPaparazziの設定をします。
https://github.com/DroidKaigi/conference-app-2022/blob/19bef1610b1daeb42e58b7e88a0dd408d3fdf0d0/preview-screenshots/build.gradle.kts

Kotlin

基本的には参考にしたPRからまるっとコピペです。
https://github.com/DroidKaigi/conference-app-2022/blob/19bef1610b1daeb42e58b7e88a0dd408d3fdf0d0/preview-screenshots/src/test/java/io/github/droidkaigi/confsched2022/ScreenshotShowkaseModule.kt

https://github.com/DroidKaigi/conference-app-2022/blob/19bef1610b1daeb42e58b7e88a0dd408d3fdf0d0/preview-screenshots/src/test/java/io/github/droidkaigi/confsched2022/PreviewScreenshotTests.kt

踏んだトラップ

Zuluはダメよ

JDKがZuluだとPaparazziが動かないからTemurinを使うことで解決しました。
https://github.com/cashapp/paparazzi/issues/565

compileSdk33はダメよ

compileSdkが33だとPaparazziが動かないのでこちらのコメントを参考に対応しました。
https://github.com/cashapp/paparazzi/issues/489#issuecomment-1195674603

@get:Rule
val paparazzi = Paparazzi(
    environment = detectEnvironment().copy(
        platformDir = "${androidHome()}/platforms/android-31",
        compileSdkVersion = 31
    ),
    maxPercentDifference = 0.0,
)

※コメントではcompileSdkVersionを32にしろと記載されてますが、32だと動かないので31にする必要があります。

ここまで行うと@PreviewのついたComposableのスクリーンショットの取得と、
スクリーンショットテストが行えます。
./gradlew recordPaparazziDebug
./gradlew preview-screenshots:verifyPaparazziDebug

CI系

スクリーンショットテスト実行

https://github.com/DroidKaigi/conference-app-2022/blob/19bef1610b1daeb42e58b7e88a0dd408d3fdf0d0/.github/workflows/ScreenShotTest.yml

      - name: Download Screenshots
        id: download-artifact
        uses: dawidd6/action-download-artifact@v2
        with:
          workflow: UpdateScreenshots.yml
          name: screenshots
          path: preview-screenshots/src/test/snapshots/images

今回は比較対象の画像をRepositoryに置かない要件なので、
artifactから比較対象の画像をダウンロードしてきます。
今回の要件ではいつ置かれたか分からないartifactをダウンロードしてくる必要があるので、
dawidd6/action-download-artifactを使用しました。

      - name: Run screenshot tests
        id: verifyPaparazziDebug
        continue-on-error: true
        run: ./gradlew preview-screenshots:verifyPaparazziDebug

ここでスクリーンショットテストを実行しています。

      - name: Error Screenshot tests
        continue-on-error: true
        if: ${{ hashFiles('preview-screenshots/out/failures/*.png') != '' }}
        uses: actions/upload-artifact@v3
        with:
          name: scrennshot-test-results
          path: preview-screenshots/out/failures

スクリーンショットテストの結果Diffがあった場合にはartifactにアップロードします。

      - name: Comment PR
        continue-on-error: true
        if: ${{ hashFiles('preview-screenshots/out/failures/*.png') != '' }}
        uses: thollander/actions-comment-pull-request@v1
        with:
          message: |
            There are differences in Compose previews. Please check your build and download the diff artifact.
            https://github.com/DroidKaigi/conference-app-2022/actions/workflows/ScreenShotTest.yml
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

スクリーンショットテストでDiffがあった時にはPRにコメントします。
※本当はDiffのartifactへリンク貼りたかったけど断念

比較用スクリーンショットの更新

https://github.com/DroidKaigi/conference-app-2022/blob/19bef1610b1daeb42e58b7e88a0dd408d3fdf0d0/.github/workflows/UpdateScreenshots.yml
こちらは面白いことは特にしていません
PRがマージされたタイミングでスクリーンショットのレコードとartifactへのアップロードを行っています。

最後に

新しい環境だとPaparazziが不機嫌になることが多かったのですが、
踏める範囲では全て踏んだつもりなので、ぜひ試してみてください!!

Discussion