Playwrightで遷移先ページのタイトルを評価しようとしたら成功したり失敗したりした
起こったこと
Playwrightで遷移先ページのタイトルを評価しようとしたら成功したり失敗したりとフレイキーなテストになってしまった。
Version
"@playwright/test": "^1.28.1"
コード
対象HTML
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>test</title> </head> <body> <main> <a href="https://ja.wikipedia.org/wiki/%E5%8F%8D%E5%B0%84%E6%98%9F%E9%9B%B2" target="_blank">反射星雲</a> </main> </body> </html>
Playwrightでは
import { test, expect } from "@playwright/test"; // baseUrlはlocalhostが設定されている test("Wikipediaへ別タブで遷移する", async ({ page }) => { await page.goto("/link.html"); const [page1] = await Promise.all([ page.waitForEvent("popup"), page.getByRole("link", { name: "反射星雲" }).click(), ]); expect(await page1.title()).toBe("反射星雲 - Wikipedia"); });
たまにfailする
こうした
DOMがロードされるのを待つようにした
import { test, expect } from "@playwright/test"; // baseUrlはlocalhostが設定されている test("Wikipediaへ別タブで遷移する", async ({ page }) => { await page.goto("/link.html"); const [page1] = await Promise.all([ page.waitForEvent("popup"), page.getByRole("link", { name: "反射星雲" }).click(), ]); await page.waitForLoadState("domcontentloaded"); // ここを追加 expect(await page1.title()).toBe("反射星雲 - Wikipedia"); });
安定するようになった。気がする。たまたまフレイキーなテストが成功し続けているだけかもしれない。
Playwrightで新規ページのURLをアサートしたい
起こったこと
Playwrightでページ遷移のテストは書けるが、新規ページで開かれるURLのアサートの仕方がわからない。
version
@playwright/test: "^1.28.1"
コード
test("foobartest", await ({ page, context }) =>{ const [newPage, _] = await Promise.all([ context.waitForEvent('page'), page.getByLabel("TEXT"), ]) await expect(newPage).toHaveURL("URL_OR_PATH"); });
JavascriptでBasic認証のついたURLから認証情報だけ消したURLを取得したい
起こったこと
Basic認証のついたURLを必要としており、かつ必要に応じてこのURLを表示したい。ただ、表示するときにBasic認証がそのままついた状態だと困る。そのため、Basic認証のついたURLから認証情報だけを外したい。
例
- https://username:password@testtest.com + https://testtest.com
コードはこう
const removeBasicAuth = (urlWithBasicAuth) => { const url = new URL(urlWithBasicAuth); url.username = ""; url.password = ""; return url.toString(); }; const targetUrl = "https://username:password@testtest.com"; const url = removeBasicAuth(targetUrl); console.log(url); // "https://testtest.com"
フロントエンドではE2Eテストだけでも書くようにした
起こったこと
現在運用中のフロントエンドだけで動いているWebアプリケーションについて、テストコードが全く書かれていない状態だったので、ユニットテストなどをいろいろすっ飛ばしてE2Eテストだけでも書くようにした。
やったこと
とにかく既存機能のE2Eテストを書く
今の動いている通常の機能だけでもE2Eテストを書いた。これから出来る新機能やバグ修正パッチが完成する前に作り終えないと、これから発生するエンバグの時期がわからなくなる。E2Eを作成中に出来上がった新機能についてはいったん考えない。とにかく既存機能にテストを書く。
既知のバグを再現する手順をテストを書く
かつて発生したバグが出た操作をE2Eに記載する。既知のバグで修正済みのはずなので、実行すればパスするはず。だよね?
ユーザーの動きに近い再現方法を書くのが良いのか、それとも機械的に最短で再現できる方法を書くのが良いか、いつも迷う。
新機能や新バグを見つけたときは都度E2Eに追加していく
上の2つが出来たら開発チームに横連携して、レビュー、マージする。チームには新機能を開発する、あるいはバグが発生したときは都度E2Eを書くようお願いする。
あきらめたこと
PlayWrightでいろんなブラウザで起動すること
PlayWrightには3つぐらいブラウザが同時に実行されるけど重いからChromeだけでも動かすようにした。これ本当にCIで実行できるのだろうか。
E2Eだけでテストを網羅すること
受け入れテストを完全にE2Eで自動化に出来そうだと思ったけど、やっぱり人によるの検証は別途必要そう。モンキーテストのような、そういうテストは人間がやらないとだめだ。特に文章がおかしいとか、文字がはみ出ているといったテストは人間がやらないと見つからなさそう。書いていること以外のことはできないのがE2Eなんだと思った。
頑張りすぎること
もう少し頑張ったらきれいで汎用性の高いものがかけそうだったものがあるのだが、まずは終わらせることを目標とした。そうじゃないと延々とテストコードを書き続けることになりそう。終わりがないのが終わり。
テストコードがあると安心
つぎはぎ感があるがテストコードがかけた。これがあると新機能を作るときにもエンバグの怖さがだいぶ減る。書いてよかった。いま、テストコードが足りていないアプリについてはテストコードを書くようにしよう。
WindowsでもReactNativeが動いた(ReactNative for Windows + macOS)
Node.jsで複数のJSONファイルを1つにまとめたい
バージョン情報
$ node -v v16.15.1
起こったこと
特定のディレクトリ内にある複数のJSONファイルをを1つにしたいという要望が出た。
JSONファイルの名前をKeyにして、中身をvalueとしてを持つような単純なものである。
例
hogehoge.json
{ "name": "aiueo" }
piyopiyo.json
{ "weight": 60 }
まとめた後のjson
{ "hogehoge": { "name": "aiueo" }, "piyopiyo": { "weight": 60 } }
つくったもの
大した理由ではないがTypeScriptではなくNode.jsで書くことにした。
// merge_json.js const path = require("path"); const fs = require("fs"); const printUsage = () => { console.log("Usage: node merge_json.js <path_to_jsons_dir>"); process.exit(1); }; if (process.argv.length < 3) { printUsage(); } const dir = process.argv[2]; const target = path.resolve(process.cwd(), dir); const mergedJson = {}; const removeExtension = (filename) => { return filename.replace(/\.json/, ""); }; fs.readdirSync(target).forEach(fileName => { if (!/\.json$/.test(fileName)) return; const json = fs.readFileSync(path.resolve(target, fileName), { encoding: "utf-8" }); const key = removeExtension(fileName); mergedJson[key] = JSON.parse(json); }); fs.writeFileSync(process.cwd() + "/merged.json", JSON.stringify(mergedJson, null, 2), { encoding: "utf-8" });
ターミナルからnode merge_json DIR_PATH
と入力すればマージされたJSONがmerged.json
という名前で出力される。