Rayrun
← Back to Discord Forum

Login Fixture with multiple user roles

Hello! In my project, we are going to start using Sauce Labs. So far, I have been using this method (https://playwright.dev/docs/auth#multiple-signed-in-roles ) to reuse the login state, but when running tests in parallel in SauceLabs, they fail cause they never gets to the login state. I understand that each worker is an independent machine and the setup dependency will only be executed in the first worker. I'm trying to test using the worker fixture from the documentation, but it doesn't exactly explain how to do it to save the state of multiple different users.

This thread is trying to answer question "How can I use Login Fixture with multiple user roles in Sauce Labs and Playwright to save the state of multiple different users?"

11 replies

I have modified the code from the documentation slightly, but I can't get it to work correctly. When running the tests, I get the following error: Error: Cannot provide fixture value for the second time. Any idea how can i approach this ?

import fs from 'fs';
import path from 'path';
import { LoginPage } from '../pages/login.page';
import { user } from '../data/users.json';

export * from '@playwright/test';

export const test = baseTest.extend<{}, { workerStorageState: string }>({
  // Use the same storage state for all tests in this worker.
  storageState: ({ workerStorageState }, use) => use(workerStorageState),

  // Authenticate once per worker with a worker-scoped fixture.
  workerStorageState: [
    async ({ browser }, use) => {
      // Use parallelIndex as a unique identifier for each worker.
      const id = test.info().parallelIndex;

      user.forEach(async (userInfo) => {
        const fileName = path.resolve(`playwright/.auth/${userInfo.role}${id}.json`);

        if (fs.existsSync(fileName)) {
          // Reuse existing authentication state if any.
          await use(fileName);
          return;
        }

        // Important: make sure we authenticate in a clean environment by unsetting storage state.
        const page = await browser.newPage({ storageState: undefined });

        // Perform authentication steps. Replace these actions with your own.
        const login = new LoginPage(page);


        await login.gotoUrl();
        await login.loginAction(userInfo.userName, userInfo.pass)

        // Wait until the page receives the cookies.
        //
        // Sometimes the login flow sets cookies during several redirects.
        // Wait for the final URL to ensure that the cookies are actually set.
  
        // Alternatively, you can wait until the page reaches a state where all cookies are set.

        // End of authentication steps.

        await page.context().storageState({ path: fileName });
        await page.close();
        await use(fileName);
      });
    },
    { scope: 'worker' },
  ],
});```

Has no one faced a similar problem? Can anyone help me?

Why do you have export * from @playwrigt-test?

Because it is in the code example of the documentation https://playwright.dev/docs/auth#moderate-one-account-per-parallel-worker

If I delete the export the result is the same anyways

Maybe it requires another approach, actually the code saves the storage state of every user but when I enter to the first if if (fs.existsSync(fileName)) { // Reuse existing authentication state if any. await use(fileName); return; } it fails with this error: ```Error: Cannot provide fixture value for the second time

at ..\src\fixtures\fixture.ts:23

  21 |         if (fs.existsSync(fileName)) {
  22 |           // Reuse existing authentication state if any.
> 23 |           await use(fileName);
     |                 ^
  24 |           return;
  25 |         }
  26 |

    at forEach (C:\proyectos\GsmartTesting\src\fixtures\fixture.ts:23:17)
    at Object._test.test.extend.workerStorageState.scope (C:\proyectos\GsmartTesting\src\fixtures\fixture.ts:18:13)```

If i delete the if and assign the storage state in the test with ``` const id = process.env.TEST_PARALLEL_INDEX const storageFile = path.resolve(playwright/.auth/${user.role}${id}.json);

test.use({ storageState: storageFile });```I get an error cause the fixture doesn't execute and the test can't read the storagestate cause it never its saved

maybe a solution could be to have a different fixture for every user ( as I only have three kind of users in the app ), but this duplicates the test code for every user and doesn't allow me to interact with two different users in the same test

MisiaMiszka

I was struggling with this one as well. I think my solution work now - I will write to you here in the afternoon. It is sad that you didn't get much help here. I have to start use discord more as well

@MisiaMiszka Hi!! Thanks for the reply!! I just saw your message. For now I have found a solution parameterizing the login using the worker fixture and project options (https://playwright.dev/docs/test-parameterize#parameterized-projects), but in this way I have to define a project for each test suite contained in a spec file, it works but I would prefer to do it directly in the fixture saving myself all those extra projects. If you have found a solution please share it right here so everyone can use it!

TwitterGitHubLinkedIn
AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email luc@ray.run.