
Slackにカスタムメッセージを送るのは簡単だけど、メッセージにReportPortalのLaunch(テスト実行とテスト結果を含むオブジェクト)のURLを追加するのがとても難しかった。結論を言うとカスタムメッセージは同期型のcustomLayoutと非同期型のcustomLayoutAsyncがあり、APIなどでデータを取ってきてカスタムメッセージに追加するには後者を利用する必要がある。
非同期のカスタムレイアウトに気がつけなかった理由
カスタムレイアウトの説明は以下にある。
Define your own Slack message custom layout
1つ目のサンプルをベースに作ってみたが、Slackへの通知で以下のようにエラーになった。
{
"outcome": "error: {\n \"code\": \"slack_webhook_http_error\",\n \"original\": {\n \"message\": \"Request failed with status code 400\",\n \"name\": \"AxiosError\",\n \"stack\": \"AxiosError: Request failed with status code 400\\n at settle (/Users/daipresents/Work/playwright/node_modules/axios/lib/core/settle.js:19:12)\\n at IncomingMessage.handleStreamEnd (/Users/daipresents/Work/playwright/node_modules/axios/lib/adapters/http.js:589:11)\\n at IncomingMessage.emit (node:events:531:35)\\n at endReadableNT (node:internal/streams/readable:1696:12)\\n at processTicksAndRejections (node:internal/process/task_queues:82:21)\\n at Axios.request (/Users/daipresents/Work/playwright/node_modules/axios/lib/core/Axios.js:45:41)\\n at processTicksAndRejections (node:internal/process/task_queues:95:5)\\n at IncomingWebhook.send (/Users/daipresents/Work/playwright/node_modules/@slack/webhook/src/IncomingWebhook.ts:70:24)\\n at SlackWebhookClient.sendMessage (/Users/daipresents/Work/playwright/node_modules/playwright-slack-report/src/SlackWebhookClient.ts:36:16)\\n at SlackReporter.onEnd (/Users/daipresents/Work/playwright/node_modules/playwright-slack-report/src/SlackReporter.ts:117:29)\\n at ReporterV2Wrapper.onEnd (/Users/daipresents/Work/playwright/node_modules/playwright/lib/reporters/reporterV2.js:91:12)\\n at wrapAsync (/Users/daipresents/Work/playwright/node_modules/playwright/lib/reporters/multiplexer.js:79:12)\\n at Multiplexer.onEnd (/Users/daipresents/Work/playwright/node_modules/playwright/lib/reporters/multiplexer.js:51:25)\\n at InternalReporter.onEnd (/Users/daipresents/Work/playwright/node_modules/playwright/lib/reporters/internalReporter.js:69:12)\\n at Runner.runAllTests (/Users/daipresents/Work/playwright/node_modules/playwright/lib/runner/runner.js:77:28)\\n at runTests (/Users/daipresents/Work/playwright/node_modules/playwright/lib/cli.js:132:93)\\n at t.<anonymous> (/Users/daipresents/Work/playwright/node_modules/playwright/lib/cli.js:42:7)\",\n \"config\": {\n \"transitional\": {\n \"silentJSONParsing\": true,\n \"forcedJSONParsing\": true,\n \"clarifyTimeoutError\": false\n },\n \"adapter\": [\n \"xhr\",\n \"http\"\n ],\n \"transformRequest\": [\n null\n ],\n \"transformResponse\": [\n null\n ],\n \"timeout\": 0,\n \"xsrfCookieName\": \"XSRF-TOKEN\",\n \"xsrfHeaderName\": \"X-XSRF-TOKEN\",\n \"maxContentLength\": -1,\n \"maxBodyLength\": -1,\n \"env\": {},\n \"headers\": {\n \"Accept\": \"application/json, text/plain, */*\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"@slack:webhook/7.0.2 node/21.6.2 darwin/23.3.0\",\n \"Content-Length\": \"21\",\n \"Accept-Encoding\": \"gzip, compress, deflate, br\"\n },\n \"baseURL\": \"https://hooks.slack.com/services/XXXXXXXXXX\",\n \"maxRedirects\": 0,\n \"proxy\": false,\n \"method\": \"post\",\n \"url\": \"https://hooks.slack.com/services/XXXXXXXXXX\",\n \"data\": \"{\\\"unfurl_links\\\":true}\"\n },\n \"code\": \"ERR_BAD_REQUEST\",\n \"status\": 400\n }\n}"
}
レイアウトからはSlackメッセージのブロックを返さなければならないのに非同期になりPromiseが返ってしまって400 Bad requestになっているみたい。
ここで1日詰まってしまったが、どうやってデフォルトのブロック作ってるのかソースを追っかけてみると、SlackWebhookClient.ts に customLayoutAsync たるものを発見。
Define your own Slack message custom layoutを改めてみてみると、別のサンプルのところにこんな記述があった。
In your, playwright.config.ts file, add these params (Make sure you use layoutAsync rather than layout):
これに気がつけなかったー。そのかわりに、Promise/async/awaitの勉強ができた。
Slackカスタムメッセージを作成する
PlaywrightからReportPortalにつなぎこみ、テストを実行すると最後に以下のログが出る。
ReportPortal Launch Link: http://localhost:8080/ui/#playwrightwithreportportalproject/launches/all/240
このリンクはclient-javascript というライブラリのreport-portal-clinet.jsで出力しているようだ。このリンクをクリックすれば、実行結果画面にすぐ行けるんだけど、このURLデータがどこにも見当たらないので自分で作るしかない。
幸いReportPortalにはAPIがたくさんあるので、今回は/launch/latestというREST APIを使える。リンクを作るためには↑だと 240のようなLaunchのIDが必要になる。
まずは非同期型のジェネレーターを作成する(サンプルコード)。
...
export async function generateReportPortalLayoutAsync (summaryResults: SummaryResults): Promise<Array<KnownBlock | Block>> {
const blocks = await generateBlocks(summaryResults, summaryResults.failed);
// add link to summary
const permalink = await getReportLink();
blocks[1]['text']['text'] = `${blocks[1]['text']['text']}\nSee: <${permalink}>`;
return blocks;
}
...
デフォルトのカスタムメッセージはわかりやすいのでgenerateBlocks()を使って生成。そして、getReportLink()でReportPortalAPIからデータを取得しLaunchのリンクを作成する。これをgenerateBlocks() で作ったSlackのブロックに追記した。
そしてplaywright.config.tsには以下のように記述する。layoutAsync になっているので注意。
...
reporter: [
['@reportportal/agent-js-playwright', reportPortalConfig],
[
"./node_modules/playwright-slack-report/dist/src/SlackReporter.js",
{
slackWebHookUrl: process.env.SLACK_HOOK,
//channels: ["general"],
sendResults: "always", // "always" , "on-failure", "off"
layoutAsync: generateReportPortalLayoutAsync,
},
],
],
...

結果は上のような感じになる。エラー箇所の簡易表示があり、詳細を見るならReportPortalを開けばいい。デバッグ捗りそう。