Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.qawolf.com/llms.txt

Use this file to discover all available pages before exploring further.

Use Playwright’s getDisplayMedia API with Chrome flags to record audio playing in a browser tab. The recording is saved as a .webm file that can be downloaded and analyzed.
Playwright initializes the fake audio device once per browser instance. You cannot swap audio sources mid-flow. If you need to record different audio content, launch a new browser instance for each.

Examples

Record audio from a browser tab
const { rm } = await import("node:fs/promises");
await rm("/tmp/audioRecording.webm", { force: true });

page.on("download", async (download) => {
  await download.saveAs(`/tmp/${download.suggestedFilename()}`);
});

await page.evaluate(async () => {
  const stream = await navigator.mediaDevices.getDisplayMedia({
    video: { displaySurface: "browser" },
    audio: { displaySurface: "browser" },
  });

  const recorder = new MediaRecorder(stream);
  window.__rec = recorder;

  const chunks = [];
  recorder.ondataavailable = (e) => chunks.push(e.data);

  recorder.onstop = () => {
    const blob = new Blob(chunks, { type: chunks[0]?.type || "video/webm" });
    stream.getVideoTracks()[0]?.stop();

    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = "audioRecording.webm";
    document.body.appendChild(a);
    a.click();
    a.remove();
  };

  recorder.start();
});

// trigger audio playback in your app

await page.waitForTimeout(10_000);
await page.evaluate(() => window.__rec.stop());
await page.waitForTimeout(10_000);
Download audio from a page element If your app exposes audio via a <video> or <audio> element, download it directly without screen capture:
const audioUrl = await page.locator("video").getAttribute("src");

const [download] = await Promise.all([
  page.waitForEvent("download"),
  page.evaluate((url) => {
    const link = document.createElement("a");
    link.href = url;
    link.setAttribute("download", "audio.m4a");
    document.body.appendChild(link);
    link.click();
    link.remove();
  }, audioUrl),
]);

const filePath = await download.path();

When to use

  • Your app streams or plays audio and you need to verify the correct audio played.
  • Your app generates audio output and you need to capture it for analysis.
  • Your test needs to validate audio content that can’t be asserted through the UI.
  • Your app has a media player and you need to confirm playback works end to end.

Full sample test

import { flow, launch } from "@qawolf/flows/web";

export default flow(
  "Record browser audio",
  "Web - Chrome",
  async ({ test }) => {
    const { context } = await launch({
      permissions: ["microphone", "camera", "clipboard-read", "clipboard-write"],
      args: [
        "--enable-experimental-web-platform-features",
        "--use-fake-device-for-media-stream",
        "--use-fake-ui-for-media-stream",
        "--enable-usermedia-screen-capturing",
        "--auto-select-desktop-capture-source=Entire screen",
      ],
    });

    const page = await context.newPage();

    await test("record audio and verify file was captured", async () => {
      // Arrange
      await page.goto("https://your-app.com/player");
      await page.locator(`[data-testid='play-button']`).waitFor({ state: "visible" });

      const { rm, access } = await import("node:fs/promises");
      await rm("/tmp/audioRecording.webm", { force: true });

      page.on("download", async (download) => {
        await download.saveAs(`/tmp/${download.suggestedFilename()}`);
      });

      await page.evaluate(async () => {
        const stream = await navigator.mediaDevices.getDisplayMedia({
          video: { displaySurface: "browser" },
          audio: { displaySurface: "browser" },
        });

        const recorder = new MediaRecorder(stream);
        window.__rec = recorder;

        const chunks = [];
        recorder.ondataavailable = (e) => chunks.push(e.data);

        recorder.onstop = () => {
          const blob = new Blob(chunks, { type: chunks[0]?.type || "video/webm" });
          stream.getVideoTracks()[0]?.stop();

          const a = document.createElement("a");
          a.href = URL.createObjectURL(blob);
          a.download = "audioRecording.webm";
          document.body.appendChild(a);
          a.click();
          a.remove();
        };

        recorder.start();
      });

      // Act
      await page.locator(`[data-testid='play-button']`).click();
      await page.waitForTimeout(10_000);
      await page.evaluate(() => window.__rec.stop());
      await page.waitForTimeout(10_000);

      // Assert
      async function exists(p) {
        try { await access(p); return true; } catch { return false; }
      }
      expect(await exists("/tmp/audioRecording.webm")).toBeTruthy();
    });
  },
);
Last modified on May 20, 2026