Playwrightで画面外のloading=’lazy’な画像もscreenshotに含める

2023/02/27

最終更新:2023/04/12

imgタグにloading='lazy'を指定すると画像読み込みをビューポートに入るまで保留してくれる(lazy loading)。これは一般的にパフォーマンスが上がるとされていて、Next.jsが提供するImageコンポーネントではデフォルトの機能として提供されている。

自分のブログにVRTを導入しようとPlaywrightを触っている際に、fullpageでscreenshotを撮ろうとするとlazy loadingな画像がscreenshotに含まれたり含まれなかったり、そもそもコンテンツ下部に画像があったりして読み込まれていなかったりして苦戦したのでメモ。

flakyな様子

解決策

最下部までスクロールダウン→スクロールトップ

原始的だが確実。Playwrightのメンテナも言っている

やっていることはdocument.body.scrollHeightの値を見ながらwindow.scrollToによるscrollを行っているだけである。

await page.evaluate(async () => {
    const delay = (ms: number) =>
      new Promise((resolve) => setTimeout(resolve, ms))

    // scroll to bottom
    for (let i = 0; i < document.body.scrollHeight; i += 100) {
      window.scrollTo(0, i)
      await delay(50)
    }

    // scroll to top
    for (let i = document.body.scrollHeight; i > 0; i -= 100) {
      window.scrollTo(0, i)
      await delay(50)
    }
  })

await expect(page).toHaveScreenshot({ fullPage: true })

delayを少しかけることでsmooth scrollを表現している。100や50という数字はテストの実行速度に影響するので必要に応じてチューニングする。

このdelayはevaluateのコールバック内で宣言しないとReference Errorになる。

page.mouse.wheelでもスクロールできるが、一部サポートがないAPIなのでwindow.scrollToのほうがよさそう。

全体的なサンプルコードはこちら

lazy loadingを使わない

例えばこの記事では画像を記事全体に渡って載せていて、少し早めのスクロールをすると画像読み込みが間に合わずちらつきが発生する(チューニングしろという話ではある)。SSGやISRを行っている時点で個人ブログ程度であれば一定のパフォーマンスは出るので、lazy loadingをやめても実は支障がないかもしれないし、ちらつきが発生しない分ユーザー体験は上がるかもしれない。このブログも検証次第ではlazy loadingをやめるかも。

参考

https://developer.mozilla.org/ja/docs/Learn/HTML/Howto/Author_fast-loading_HTML_pages#画像の遅延読み込みを使用する

https://developer.mozilla.org/ja/docs/Web/API/HTMLImageElement/loading#値

https://github.com/microsoft/playwright/issues/19277

by me a coffee