microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
65.41k stars 3.56k forks source link

[Feature] improve / establish fake media definition via config #27436

Open dacloutier-logmein opened 11 months ago

dacloutier-logmein commented 11 months ago

I thought that making use of test-use-options would be way to go. Unfortunately, it did not work. No audio would come out. ref: https://playwright.dev/docs/test-use-options

Worse yet, the moment that test.use({}) is defined (even if empty) is enough to break the audio playback.

System info

Source code

I've made it generic enough to share, but that's the gist of the test setup.


test.use({
  launchOptions: {
    args: [
         "--use-fake-ui-for-media-stream",
         "--use-fake-device-for-media-stream",
         '--use-file-for-fake-audio-capture=../resources/audio/someaudio_file.wav%noloop'
    ]
  }
});

test.beforeEach(async () => {
  const browserName = test.info().project.use.defaultBrowserType;

  let userOneBrowser: Browser;
  let userTwoBrowser: Browser;
  let userOneContext: BrowserContext;
  let userTwoContext: BrowserContext;
  let userOnePage: Page;
  let userTwoPage: Page;

 [userOneBrowser, userTwoBrowser] = await
        Promise.all([
          // Leave as is, in order to load the audio file
          chromium.launch({}),
          chromium.launch({
            args: [
              // Those prevents the browser from using the previous camera and microphone settings
              // and by "accident" the audio file we are using for the test
              // we do not want both end of the conversation to play the audio file
              "--use-fake-ui-for-media-stream",
              "--use-fake-device-for-media-stream"
            ]
          })
        ]);

      [userTwoContext, userOneContext] = await
        Promise.all([
          userTwoBrowser.newContext({ recordVideo: { dir: "results/videos/userTwo" }, permissions: ['camera', 'microphone', 'clipboard-read'] }),
          userOneBrowser.newContext({ recordVideo: { dir: "results/videos/userOne" }, permissions: ['camera', 'microphone', 'clipboard-read'], })
        ]);

  console.log("Browsers initialized");

  [userTwoPage, userOnePage] = await Promise.all([userTwoContext.newPage(), userOneContext.newPage()]);
});

test("Sample Test", async () => {
    // Navigate to any page that would allow you to playback the audio, in our case, it's a WebRTC application
});

Link to the GitHub repository with the repro

Cannot provide, against Acceptable Use Policy from work.

or

Config file

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  projects: [
    {
      name: "chromium",
      use: {
        ...devices["Desktop Chrome"],
        permissions: ['camera', 'microphone', 'clipboard-read'],
        launchOptions: {
          args: [
            '--use-fake-ui-for-media-stream',
            '--use-fake-device-for-media-stream',
            '--use-file-for-fake-audio-capture=src/resources/audio/someaudio_file.wav%noloop'
          ],
        },
      },
    }
});

Test file (self-contained)

Unfortunately, cannot provide , as it is against the AUP.

Steps

Expected

[Describe expected behavior]

Actual

No audio is played back if the source audio file is passed via the test.use({...})

Note: I've also tried to set the audio source as launchOptions: args[....] that didn't help either.

dacloutier-logmein commented 11 months ago

@pavelfeldman Thanks for the title edit, didn't realized I forgot to add one. Let me know if more details are needed.

dacloutier-logmein commented 6 months ago

FYI, I've finally worked around the issue by using tests fixtures.

audioFileName: [async ({ }, use) => {
      const audioFileName = 'randomAudioFile'
      await use(audioFileName)
},
{ scope: 'worker' }

....

browser: [async ({ audioFileName }, use) => {
      const browser: Browser = await chromium.launch(
        {
          args: [
            '--use-fake-ui-for-media-stream',
            '--use-fake-device-for-media-stream',
            `--use-file-for-fake-audio-capture=PATH_TO_FILE/${audioFileName}%noloop`
          ]
        }
      )
      await use(browser)
    },
    { scope: 'worker', auto: false },
    ],

Unfortunately only worked with chrome, but it's still better than nothing.

mindriven commented 1 month ago

Hey @dacloutier-logmein, thanks for sharing! I'm facing similar problem, just webcam instead of mic. I understood you made it work with worker fixture, but with your code fragments I can't make it work for me. I have written the code below, where TS does not complain, but when I use this test in my file, playwright stops recognizing the tests as tests. Any chance you can share a bit more? Also, maybe since your last comment you have found a way to make it work per-test, not per worker?

export type WebCamInjectionTestOptions = {
  webCamInjectionFile: string;
};

const base2 = base.extend<object, WebCamInjectionTestOptions>({
  webCamInjectionFile: [
    async (_, use) => {
      const webCamInjectionFile = 'please sepcify webCamInjectionFile';
      await use(webCamInjectionFile);
    },
    { scope: 'worker', auto: false },
  ],
});

export const test = base2.extend<object, object>({
  browser: [
    async ({ webCamInjectionFile }, use) => {
      const browser: Browser = await chromium.launch({
        args: [
          '--use-fake-device-for-media-stream',
          '--use-fake-ui-for-media-stream',
          `--use-file-for-fake-video-capture=${webCamInjectionFile}`,
        ],
      });
      await use(browser);
    },
    { scope: 'worker'},
  ],
});