Playwright Tips
参考Zenn
ありがとうございます〜!
git actionsのcron時間
Playwright チートシート
並列処理テスト実行
test.describe.parallel("Visual regression testing of page", () => {
何かテストを記載
})
parallelで中に書いてあるテストを順番にではなく、並列で処理できる。
スナップショットを撮り、UIの変化がないかテスト
// pageのスナップショットを撮るテスト関数
const takeSnapShot = async (page: Page, name: string) => {
expect(await page.screenshot({ fullPage: true })).toMatchSnapshot([
name,
`${name}.png`,
]);
};
使い方
const baseUrl = "https://hogehoge.com"
const pagePathForSnapShotTest = [
// ここに各ページの情報を追加
{
name: "home",
path: `${baseUrl}`,
},
{
name: "about",
path: `${baseUrl}about/`,
},
];
test.describe.parallel("Checking drawing", () => {
pagePathForSnapShotTest.map((item) => {
test(`snapshot test ${item.name}`, async ({ page }) => {
await takeSnapShot(page, `${item.name}`);
})
});
});
画像の描画を待ってから処理を行いたい時
const waitForImageLoad = async (page: Page) => {
const imgElements = await page.$$("img");
const imageLoadPromises = imgElements.map(async (imgElement) => {
if (imgElement) {
await imgElement.evaluate((node) => {
return new Promise<void>((resolve) => {
if (node.complete) {
resolve();
} else {
node.addEventListener("load", () => {
resolve();
});
}
});
});
}
});
await Promise.all(imageLoadPromises);
};
2023.12.5追記
const waitForImageLoad = async (page: Page) => {
for (const img of await page.getByRole("img").all()) {
await expect(img).toHaveJSProperty("complete", true);
await expect(img).not.toHaveJSProperty("naturalWidth", 0);
}
};
evaluateとは
Playwright スクリプト内でブラウザのページ上で JavaScript コードを実行するためのメソッド
拡張機能
Playwright Test for VSCode
vs code上でデバックなどが行える
要素複数選択
厳格性
例) locatorで要素を指定する
await page.locator(".class名 a").click();
このような時に下記エラーが出る場合が...。
Error: locator.click: Error: strict mode violation: locator('.mf_finder_drilldown_reset a') resolved to 2 elements:
これはplaywrightなどのテストでどれを最終的にクリックしたらいいの?と聞いてきてる。
ですので、テストコードを書くときは厳格に要素を指定してあげてみたらGood!!
exact
nameを完全に大文字と小文字を区別し、文字列全体をマッチさせるもの。
デフォルトはfalse。
name が正規表現の場合は無視される。
完全一致でも空白は切り捨てられることに注意。
await page.getByRole("link", { name: "top", exact: true }).click();
何を持ってしてkey down系の操作を正とするか
await page.getByPlaceholder("検索ボックス").press("ArrowDown");
などのkey系の操作はどのようにできてるできてないを判断するの...??
playwright test-report
http://localhost:9323
初期だと上記URLで開く。(テストに失敗すると勝手に開く)
portがたまに使えない時が訪れるので
lsof -i
で動いてるportを確認してみて
kill -9 プロセスID
でkillすれば解決
※間違って違うプロセスを消さないように!!!
Best Practices
-
ロケータを使う
エンドツーエンドのテストを書くには、まずウェブページ上の要素を見つける必要があります。これを行うには、Playwrightに組み込まれているロケータを使用する。ロケーターには自動待機とリトライ機能が付いている。自動待機とは、Playwrightがクリックを実行する前に、要素が表示されていて有効になっていることを確認するなど、要素に対してさまざまな実行可能性チェックを行うことを意味します。テストに弾力性を持たせるために、ユーザー向けの属性と明示的な契約を優先することをお勧めします。 -
ロケータの生成
Playwrightには、テストを生成してロケータを選択するテストジェネレータがあります。ページを見て、ロール、テキスト、テスト ID ロケータを優先して、最適なロケータを決定します。ロケータにマッチする要素が複数見つかった場合は、ロケータを改良して弾力性を持たせ、ターゲット要素を一意に識別できるようにします。 -
ウェブ・ファーストのアサーションを使う
アサーションは、期待する結果と実際の結果が一致するかどうかを検証するための方法です。ウェブファーストアサーションを使用することで、Playwright は期待する条件が満たされるまで待機する。例えば、アラートメッセージをテストする場合、テストはメッセージを表示させるボタンをクリックし、アラートメッセージがあるかどうかをチェックする。アラートメッセージが表示されるまでに 0.5 秒かかる場合、toBeVisible() などのアサーションは待機し、必要に応じて再試行します。 -
デバッグの設定
ローカルデバッグのためには、VS Code エクステンションをインストールして、VSCode でテストをライブデバッグすることをお勧めします。デバッグモードでテストを実行するには、実行したいテストの横の行を右クリックしてブラウザウィンドウを開き、ブレークポイントが設定された場所で一時停止します。 -
Playwrightの依存関係を最新に保つ
Playwrightのバージョンを最新に保つことで、最新のブラウザバージョンでアプリをテストし、最新のブラウザバージョンが一般公開される前に不具合を検出することができます。
アサーション
あるコードが実行される時に満たされるべき条件を記述して実行時にチェックする仕組みをアサーションという
アサーションの例
// div.classがあるか調べる
// 要素のセレクター
const elementSelector = "div.class";
// 要素が存在するか確認
const isElementExists = await page
.waitForSelector(elementSelector, { timeout: 5000 })
.then(() => {
console.log("element is found");
return true;
})
.catch(() => {
console.log("element is not found");
return false;
})
// ここでtrue出ないとテストがストップする
// アサーション
expect(isElementExists).toBeTruthy();
アサーション
console errorの確認
const pageErrors: any[] = [];
page.on("pageerror", (exception) => pageErrors.push(exception));
expect(pageErrors).toMatchObject([]);
selectorに苦戦した話
<select
:name="name"
v-model="categoryCurrent"
@focus="onFocusSelect"
@blur="onBlurSelect"
@change="onChangeSelect"
>
<option
v-if="!disableCategoryAll"
class="class_opt_0"
value=""
>
{{ categoryAllText }}
</option>
<option
v-for="(val, i) in categoryValues"
:key="i"
:class="'class_opt_' + (i + 1)"
:value="val"
>
{{ val }}
</option>
</select>
↓ 出力
<select name="name" class="class">
<option value="" class="class_opt_0">
test0
</option>
<option class="class_opt_1" value="test1">
test1
</option>
<option class="class_opt_2" value="test2">
test2
</option>
<option class="class_opt_3" value="test3">
test3
</option>
</select>
こんな感じで実装されているslectorのテストを行いたいと思って
await page.getByLabel('test1 test2 test3').selectOption('test2');
と書いたら
表示はちゃんと切り替わっているのに、検索結果を絞り込めていなかった。。。
何かのバグかな?と思って
をみてみた。↓ 翻訳
へ〜って感じだったが、今回解決したいこととは関係なかったw
再度Vueで書いたコードを見てみると@focusが入っており、そのフォーカスした値がslectしている値と同じなら検索が走るという分岐が書いてあったので、一度フォーカスさせてからselectOptionをしてみた。
const selector = page.getByLabel(
"test1 test2 test3"
);
await selector.focus();
await selector.selectOption("test2");
見事OK。スナップショットで確認してみたら、通常の挙動通りに動いている様子を確認することができた。
git actionsでテストを実行
+ retries: process.env.CI ? 2 : 0,
- retries: process.env.CI ? 1 : 0,
2024.04.18
workerは1が推奨されているみたい。flakyなテストをなくすという意味でも。
snapshotPathTemplate
snapshotPathTemplate: "__screenshots__{/projectName}/{arg}{ext}",
上記のように設定すると
__screenshot__/chromium/{snapshotName}.png
となる
CI上でのfont問題
git actionでテストを実行すると、スナップショット比較の際にフォントのずれが生じてしまう。
Mac OSとgithub action(Linux環境)との差異だということでした。。。
Dockerを使用して、今回の問題を解決しようと思う。
git actions キャッシュ
公式提供のCIがあった
git actionのなかでpnpmを使用するとき
test (chromium)
The following actions uses node12 which is deprecated and will be forced to run on node16: pnpm/action-setup@v2.2.2. For more info: https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/
こんな感じでエラーが出る。
これを見るとversionによるwarningが出ていたということがわかった。
- - uses: pnpm/action-setup@v2.2.2
- with:
- version: 6.0
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 8
このように書き直したらwarningが消えた
ubuntuのバージョン
FROM mcr.microsoft.com/playwright:v1.39.0-focal
WORKDIR /app
# pnpmをインストール
RUN npm install -g pnpm
CMD [ "bash", "-c", "pnpm install && /bin/bash" ]
FROM mcr.microsoft.com/playwright:v1.39.0-jammy
WORKDIR /app
# pnpmをインストール
RUN npm install -g pnpm
CMD [ "bash", "-c", "pnpm install && /bin/bash" ]
それぞれFROMの部分が違う。
focal -> Ubuntu 20.04 LTS
jammy -> Ubuntu 22.04 LTS
とそれぞれのバージョンのコードネームになっている
accessibility
Artifactエラー
Error: Create Artifact Container failed: Artifact storage quota has been hit. Unable to upload any new artifacts
解決方法
storageの更新は遅延があるみたい。
最大1日とかかかるらしい。
上限を$1に設定すれば解決するbugも昔は起きていたっぽい
⇨これでお金はかからないと記載があったが、どうなんだろう
artifactって?
Chat-GPTくん
GitHub Actions(ギットハブアクション)では、アーティファクトとして知られるデータを扱うことができます。アーティファクトは、ビルドやデプロイの結果として生成されたファイルやデータのことです。GitHub Actionsを使用してアーティファクトを生成すると、それらをアクションの間で共有したり、後で使用したりできます。アーティファクトは、ビルドされたコードやアプリケーションの成果物、テスト結果、ログファイルなど、さまざまなものを含むことができます。これらのアーティファクトは、GitHubのUIを介して閲覧したり、他のアクションで使用したり、必要に応じてダウンロードしたりできます。
OSの変更
Playwrightの各バージョンは、特定のChromium、WebKit、Firefoxのバージョンにバインドされています。この基準を満たすために、CIプロバイダで設定することにより、異なるオペレーションシステム上でテストを実行することができますが、通常、Mac上のChromeとLinux上のChromeの間に大きな違いはありません。
私はgit actionではdockerを採用しているので、その中でmacosやwindows環境を作ればOSなどは変更できるが、こういったテストはOSの変更をするべきなのかが疑問として残った。
webkit上でtimeoutになり、pageなどが閉じてしまう現象
playwright自体が高速でテストを行うものであり、タイミング次第では閉じてしまう可能性がある
timewaitforなどで待ちすぎた結果、pageが閉じてしまう現象が起きたので調べてみた。
環境やその他テスト内容にもよるが、色々事情があるらしい。
GitHubのstorage
git actionsを利用してたらいきなり下記のようなエラーが出た。
Create Artifact Container failed: Artifact storage quota has been hit. Unable to upload any new artifacts
どうやらGitHubのstorageがartifactでいっぱいになってしまったみたいだった。
GitHubのsetting ⇨ billing and plansを確認すると下記のようになっていた。
今回は上限を$0で済むようにしてたので、課金にはならなかった。(defaultでそうなってる)
実際に今回は手動でworkflowからartifactを削除していったが、全然storageが解放されない、、、。
なぜなんだろうと調べていたところ、実際に問題が起きている人がいたし、GitHubの公式Docsにも時間がかかるとの記載が!
消してから2~3日後に解放された!!
画像圧縮 (編集中)
page.goto: Page closed
=========================== logs ===========================
navigating to "hogehoge", waiting until "load"
============================================================
await page.goto("hogehoge")
こうしないと、次の処理が非同期で走ってしまってエラーを起こしてしまう可能性がある。
アクセシビリティのテスト
チェックツールで見つけられる問題は、ウェブアクセシビリティの問題の 2割から 3割程度です。ウェブア
クセシビリティは基本的に「人がチェックする必要がある」と考えましょう。
toBeUndefined
値がundefinedかどうかをみている。
const pagePath = [
{
name: "test",
path: `${baseUrl}test/`,
},
];
test.describe.parallel("Checking undefined", () => {
pagePath.map((item) => {
test(`existence of ${item.name}`, async ({ page, browser }) => {
// pageへアクセス
await page.goto(item.path);
await page.waitForLoadState("load");
// ここで値がundefindかどうかみてる
expect('値を入れる').toBeUndefined();
});
});
});
toBe
inputValue.length(number)と100が同じかをみれる。
expect(inputValue.length).toBe(100);
waitForSelector
推奨されてないので注意!!!
pressSequentially('text',{ delay:1000 });
inputなどへ入力するとき、delayで設定した秒数で1文字ずつ入力してくれる。
速度が早過ぎで表示が確認できない時はこれで確認していく。
flaky
多少はやはり出るもの。
推奨するlocator
- page.getByRole(): To locate elements by explicit and implicit accessibility attributes.
- page.getByText(): To locate nodes by text content.
- page.getByLabel(): To locate a form control by associated label’s text.
- page.getByPlaceholder(): To locate an input by placeholder.
- page.getByAltText(): To locate an element, usually an image, by its alt text alternative.
- page.getByTitle(): To locate an element by its title attribute.
- page.getByTestId(): To locate an element based on its data-testid attribute.
timeoutで待たないほうがいい
固定の時間で待つのはよろしくない。
下記のように待つのがベスト!(その要素20個が現れたら即次のテストへ。最大10秒待つ)
expect(await page.locator('.product')).toHaveCount(20, {
timeout: 10000
});
解決方法
github actionsでのテスト速度改善案
使うCPUを買う
toMatchSnapshot
推奨されていなくて、代わりにtoHaveScreenshotを使う方がいいと書いてある
worker
2つの論理CPUコアに対して1つのワーカーを持つことを推奨します。そうしないと、過負荷の CPU ではブラウザの動作が遅くなる可能性があります。
今まで2workersでやってたが、下記のように直した。
workers: process.env.CI ? 1 : 1,
速度は
何をテスト自動化するか
このように「機能修正を行う際ふるまいが変わらない修正に対するテスト」は実行対象外とするようにしました。
無闇にテストを増やすのも考えもの
networkidle
テストには使わない方がいいらしい。他のアサーションを使うべき。
'load' - wait for the load event to be fired.
'domcontentloaded' - wait for the DOMContentLoaded event to be fired.
'networkidle' - DISCOURAGED wait until there are no network connections for at least 500 ms. Don't use this method for testing, rely on web assertions to assess readiness instead.
IMEのテストについて
WebDriver
以下のことは明らかに範囲外です:具体的な実際の入力メソッドエディタ(IME)を呼び出すことや、OS/ハードウェアレベルでの入力をシミュレートすること。これらのことは確かに場合によっては大きな利点がありますが、現在のWebDriverの仮想入力処理とは非常に異なるアプローチが必要です。
webdriverでの見解だが、全フロントエンドのテストに通じるところがあるかもしれない。
ハードデバイスごとに違う挙動になるものはテストするべきではなく、人が手動で見た方がいいかも。
playwright
色々やってるみたいだが、結論があんまり出てない