Playwrightでテスト失敗(Fail)時に画面キャプチャと動画を撮ってSlackに投稿する
情報システム室の進地@日比谷です。
Playwrightでテスト失敗(Fail)時にSlack投稿する方法として、以前、次の記事を書きました。
GitHub ActionsでPlaywright E2Eテストを定期実行し、結果をSlack通知する
失敗が通知されたその後にデバッグすることを考えると、失敗時の画面キャプチャやそこに至るまでの画面遷移の動画があるととても助かります。そこで、Slackにて失敗を通知する際に、画面キャプチャと動画も投稿する方法をご案内します。
失敗(Fail)時の画面キャプチャ、動画作成を有効化する
Playwrightには標準機能で画面キャプチャと動画作成を行う機能があります。
Trace viewer | Playwright
Videos | Playwright
具体的にはplaywright.config.ts
にて、下記の記述を行います。
export default defineConfig({
:
use: {
// 下記の3行を追加する //
trace: 'retain-on-failure',
screenshot: { mode: 'only-on-failure', fullPage: true },
video: "retain-on-failure",
},
:
});
これでエラー発生時に画面キャプチャと動画が生成されます(例ではtraceも有効化しています)。
Slackにて生成した画面キャプチャと動画を投稿する
プロジェクトルートに次のコードをcustom_layout.ts
として作成します。
import fs from 'fs';
import path from 'path';
import { Block, KnownBlock } from '@slack/types';
import { SummaryResults } from 'playwright-slack-report/dist/src';
import { WebClient } from '@slack/web-api';
import FormData from 'form-data';
const web = new WebClient(process.env.SLACK_BOT_USER_OAUTH_TOKEN);
async function uploadFileToSlack(filePath: string, filename: string, channelId: string): Promise<string | undefined> {
try {
// ファイルを読み込む
const fileContent = fs.readFileSync(filePath);
// ファイルをアップロード
const result = await web.files.uploadV2({
channel_id: channelId,
filename: filename,
file: fileContent,
});
// アップロードされたファイルの情報を取得
return result.files[0].files[0].permalink;
} catch (error) {
console.error('Error uploading file:', error);
return undefined;
}
}
export async function generateCustomLayoutAsync(
summaryResults: SummaryResults,
): Promise<Array<KnownBlock | Block>> {
const { tests } = summaryResults;
// create your custom slack blocks
const header = {
type: 'header',
text: {
type: 'plain_text',
text: '🎭 *新締処理 E2E Test Results*',
emoji: true,
},
};
const summary = {
type: 'section',
text: {
type: 'mrkdwn',
text: `✅ *${summaryResults.passed}* | ❌ *${summaryResults.failed}* | ⏩ *${summaryResults.skipped}*`,
},
};
const fails: Array<KnownBlock | Block> = [];
for (const t of tests) {
if (t.status === 'failed' || t.status === 'timedOut') {
fails.push({
type: 'section',
text: {
type: 'mrkdwn',
text: `👎 *[${t.browser}] | ${t.suiteName.replace(/\W/gi, '-')}*`,
},
});
const assets: Array<string> = [];
if (t.attachments) {
for (const a of t.attachments) {
const filePath = a.path;
const fileName = path.basename(filePath);
// ファイルをSlackにアップロード
const permalink = await uploadFileToSlack(filePath, fileName, process.env.SLACK_NOTIFY_CHANNEL_ID_ARTIFACTS);
if (permalink) {
let icon = '';
if (a.name === 'screenshot') {
icon = '📸';
} else if (a.name === 'video') {
icon = '🎥';
}
assets.push(`${icon} See the <${permalink}|${a.name}>`);
}
}
}
if (assets.length > 0) {
fails.push({
type: 'context',
elements: [{ type: 'mrkdwn', text: assets.join('\n') }],
});
}
}
}
return [header, summary, { type: 'divider' }, ...fails];
}
このコードはplaywright-slack-report
で紹介されているサンプルをベースにカスタマイズしています。サンプルはAWS S3にスナップショットと動画をアップロードしてリンクする形になっていますが、このコードではSlackにアップロードしてリンクする形にしています。
次に、必要なモジュールをインストールします。
$ npm i @slack/web-api
$ npm i form-data
最後に、playwright.config.ts
にカスタムレイアウトを使用する記述を追加します。
:
// カスタムレイアウトをimportする
import { generateCustomLayoutAsync } from './custom_layout';
:
export default defineConfig({
:
reporter: [
[
"./node_modules/playwright-slack-report/dist/src/SlackReporter.js",
{
:
// 次の1行を追加
layoutAsync: generateCustomLayoutAsync,
},
],
],
:
});
必要な環境変数の値をGitHubのsecretsに登録し、GitHub Actionsのワークフローで環境変数に設定する記述を行えば完成です。記述の仕方はこちらのコードを参考にしてください。
実行結果
次の画像のような形で、テスト実行の結果がSlack通知されます。
screenshotやvideoのリンクをクリックすると次の画像のように表示されます。
なお、通知本体(サマリー)と画面キャプチャや動画を投稿するチャンネルは分けています。
これは、投稿をまとめやすいというメリットと同時に、本体側のチャンネルにファイルが無尽蔵に増えて見通しが悪くなることを回避できるメリットがあります。