Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: run auto fixtures when new browser context created #34585

Open
yonatanai opened this issue Feb 2, 2025 · 3 comments
Open

[Feature]: run auto fixtures when new browser context created #34585

yonatanai opened this issue Feb 2, 2025 · 3 comments

Comments

@yonatanai
Copy link

yonatanai commented Feb 2, 2025

🚀 Feature Request

run auto fixtures on every new context created, or creating an event on the browser level on('new-context', (context) => { })

Example

test.use({ state: { ... } })

const test = base.extends({
  state: [{}, { option: true }]
  attachInterceptors: [
    async (
      { context, state },
      use,
    ) => {
      await context.route(); // ...
      await use();
    },

    // will run the fixture on every new context
    { auto: true, box: true, scope: 'context' },
  ],
})

or

test.use({ state: { ... } })

const test = base.extends({
  state: [{}, { option: true }]
  attachInterceptors: [
    async (
      { browser, state },
      use,
    ) => {
      await browser.on('new-context', async (context) => {
              await context.route(); // ...
     })

      await use();
    },

    { auto: true, box: true },
  ],
})

Motivation

We use auto fixtures to set up common interceptors and attach cookies to our tests.
Some of the interceptors and cookies get the data from Fixtures-options.

We encounter a problem: if we create a new browser context in our tests, the auto fixtures will not apply to this new context. It would be nice to run them on a newly created context or even to get an event that a new context created, and then we will run the callback to apply the logic of the auto fixtures on the newly created context.

Overriding the browser fixture could work, but we can't get the Fixtures-options in the override, so it does not work.

@yonatanai yonatanai changed the title [Feature]: run auto fixtures when new context created [Feature]: run auto fixtures when new browser context created Feb 2, 2025
@dgozman
Copy link
Contributor

dgozman commented Feb 3, 2025

@yonatanai I don't think this will be included in Playwright.

I'd recommend to structure your code differently, so that you run your interceptors on a new context manually. Something along these lines:

async function attachInterceptors(context) {
  await context.route(...);
  // ...
}

// Call this function manually instead of `browser.newContext()`
async function newContext(browser) {
  const context = await browser.newContext();
  await attachInterceptors(context);
  return context;
}

const test = base.extends({
  // Override "context" fixture instead of adding an auto fixture.
  context: async ({ context }, use) => {
    await attachInterceptors(context);
    await use(context);
  },
});

Let me know whether this helps.

@yonatanai
Copy link
Author

yonatanai commented Feb 3, 2025

@dgozman, thanks for the response!
This was the approach we thought to take, but it started complicating other things.
All the fixtures that use the context now should go into the newContext function or receive the context as an optional parameter; for example, we have a login: (email: string) => Promise<void> fixture that receives an email, calls an API endpoint, receives cookies and attaches them to the context, so now with the new context we need to get it as a second parameter login: (email: string, context?: BrowserContext) => Promise<void> or return "login" from the newContext function, then we lose the lazy loading of the fixtures, etc.

I try to understand if we are missing something because it seems like a common use case, and we didn't find any examples or good solutions for this problem.

@dgozman
Copy link
Contributor

dgozman commented Feb 4, 2025

@yonatanai I think it would help to make newContext a fixture of its own. In this case, it can depend and/or interact with other fixtures in any way you like. This should be pretty much the same as the feature you are asking for, but explicitly defined. Let me know whether that works.

async function attachInterceptors(context: BrowserContext) {
  await context.route(...);
  // ...
}

const test = base.extend<{ newContext: () => Promise<BrowserContext> }>({
  newContext: async ({ browser }, use) => {
    const contexts: BrowserContext[] = [];
    await use(async () => {
      const context = await browser.newContext();
      contexts.push(context);
      await attachInterceptors(context);
      return context;
    });
    await Promise.all(contexts.map(context => context.close()));
  },

  context: async ({ context }, use) => {
    await attachInterceptors(context);
    await use(context);
  },
});


test('example', async ({ newContext }) => {
  const context1 = await newContext();
  const context2 = await newContext();
  // ...
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants