コンテンツにスキップ

カメラ入力をモックする

ユースケース: アプリがカメラを使う — QR/バーコードスキャナー、本人確認書類の撮影フロー、ビデオチャットのプレビュー。用意した動画をカメラに「見せる」テストを書きたい。

Playwrightにはカメラ入力のためのAPIがなく、音声と違ってこの問題をきれいに解決するクロスブラウザのライブラリも(まだ)存在しません。あるのはブラウザごとのスイッチの寄せ集めです。

Chromium: フェイクデバイス + 動画ファイル

Section titled “Chromium: フェイクデバイス + 動画ファイル”

Chromiumは起動時にカメラをループ再生の動画に置き換えられます:

playwright.config.ts
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
launchOptions: {
args: [
'--use-fake-ui-for-media-stream', // 権限プロンプトを自動承認する
'--use-fake-device-for-media-stream', // フェイクカメラを提供する
'--use-file-for-fake-video-capture=tests/fixtures/qr-code.y4m',
],
},
},
},
],
});

ファイルは Y4M(非圧縮の生データ)またはMJPEGでなければなりません。ffmpegで何でも変換できます:

Terminal window
ffmpeg -i qr-code.mp4 -pix_fmt yuv420p qr-code.y4m

Y4Mファイルは巨大です(生フレームのため)。フィクスチャは短く小さく保ち、LFSなしでgitにコミットしないようにしましょう。

Firefox: フェイクテストストリーム

Section titled “Firefox: フェイクテストストリーム”
use: {
launchOptions: {
firefoxUserPrefs: {
'media.navigator.streams.fake': true,
'media.navigator.permission.disabled': true,
},
},
},

Firefoxは合成のテストパターンを生成します。「プレビューが描画される」ことの確認には十分ですが、内容を選べないのでQRスキャンには使えません。

WebKitと内容を制御したいストリーム: canvas注入

Section titled “WebKitと内容を制御したいストリーム: canvas注入”

どのブラウザでも特定のフレームを流したい場合は、canvasベースのストリームで getUserMedia を自前で置き換えます:

await page.addInitScript(() => {
const draw = (canvas: HTMLCanvasElement) => {
const ctx = canvas.getContext('2d')!;
const img = new Image();
img.src = '/fixtures/qr-code.png'; // フィクスチャはテストサーバーから配信する
img.onload = () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
requestAnimationFrame(() => draw(canvas));
};
};
const original = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
navigator.mediaDevices.getUserMedia = async (constraints) => {
if (!constraints?.video) return original(constraints);
const canvas = document.createElement('canvas');
canvas.width = 1280; canvas.height = 720;
draw(canvas);
const stream = canvas.captureStream(30);
if (constraints.audio) {
const audio = await original({ audio: constraints.audio });
audio.getAudioTracks().forEach((t) => stream.addTrack(t));
}
return stream;
};
});

これは playwright-audio-mocking が音声で使っているのと同じ手法です — アプリは本物の MediaStream を受け取るため、違いを検知できません。テスト中に描画する画像を差し替えれば(page.evaluate などで)、「カメラを別のものに向けた」状況をシミュレートできます。

  • --use-file-for-fake-video-capture は動画を永遠にループし、実行時に切り替えられません。
  • canvas方式は enumerateDevices() のデバイスラベル/IDをエミュレートしません(併せてパッチしない限り)。カメラ選択UIのあるアプリでは対応が必要かもしれません。
  • Linux CI上のWebKitにはカメラが一切ありません — canvas注入が唯一の道です。