When employing Playwright for parallel testing, I have noticed that my tests continue to utilize old credentials rather than obtaining fresh ones when running in parallel mode. The workers do not attempt to fetch

I have a fixture file where I attempt to sign up a new user:

import { test as baseTest, request } from '@playwright/test';
import SignUp from '../pages/SignUp';
import fs from 'fs';
import path from 'path';

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;
            const fileName = path.resolve(test.info().project.outputDir, `.auth/${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 context = await request.newContext({ storageState: undefined });
            const page = await browser.newPage({ storageState: undefined });
            // Create fake data for a user and signUp
            const signUp = new SignUp(page);
            // SignUp a new user
            await signUp.SignUp();

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

This is my playwright.config.ts file:

// @ts-check
import { defineConfig, devices } from '@playwright/test';

/**
 * Read environment variables from file.
 * https://github.com/motdotla/dotenv
 */
require('dotenv').config();

/**
 * @see https://playwright.dev/docs/test-configuration
 */
module.exports = defineConfig({
    testDir: './e2e',
    /* Run tests in files in parallel */
    timeout: 90000,
    expect: {
        timeout: 60000,
    },
    fullyParallel: true,
    /* Fail the build on CI if you accidentally left test.only in the source code. */
    forbidOnly: !!process.env.CI,
    /* Retry on CI only */
    retries: process.env.CI ? 2 : 0,
    /* Opt out of parallel tests on CI. */
    workers: process.env.CI ? 1 : undefined,
    /* Reporter to use. See https://playwright.dev/docs/test-reporters */
    reporter: 'html',
    /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
    use: {
        /* Base URL to use in actions like `await page.goto('/')`. */
        baseURL: process.env.VITE_APP_HOST,

        video: 'on',

        /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
        trace: 'on-first-retry',
    },

    /* Configure projects for major browsers */
    projects: [
        // Setup project
        {
            name: 'chromium',
            use: {
                ...devices['Desktop Chrome'],
            },
        },

        
    ],

    /* Run your local dev server before starting the tests */
    // webServer: {
    //   command: 'npm run start',
    //   url: 'http://127.0.0.1:3000',
    //   reuseExistingServer: !process.env.CI,
    // },
});

The following test involves logging in before each scenario:

// @ts-check
import { test } from '../../playwright/fixtures';
import Products from '../../pages/ProductAndServices/Products';
import Quotes from '../../pages/Quotes/Quotes';
import LoginPage from '../../pages/LoginPage';
import SignUp from '../../pages/SignUp';

test.describe('Create new product', async () => {
    let userData: { email: string; password: string; familyName: string; givenName: string; organizationName: string; phoneNumber: string };
    let loginPage: LoginPage;
    let signUp: SignUp;
    let products: Products;
    let quotes: Quotes;
    test.beforeEach(async ({ page }) => {
        loginPage = new LoginPage(page);
        signUp = new SignUp(page);
        products = new Products(page);
        quotes = new Quotes(page);
        userData = signUp.userData();
        await loginPage.Login(userData.email, userData.password);
    });

    test('Create product from Product & Services', async () => {
        await products.OpenProductsPage();
        await products.OpenNewProduct();
        await products.EnterProductName();
        await products.EnterProductDescription();
        await products.CreateNewCategory();
        await products.SelctNewCategory();
        await products.AddPurchacePrice();
        await products.AddSellingPrice();
        await products.SaveProduct();
        await products.CheckCreatedProduct();
    });
});

When running npx playwright test, some tests fail due to invalid credentials. How can I modify my fixtures.ts file to ensure signup by a new user for each test on each worker?

Thank you for your assistance in advance.

Answer №1

The issue was resolved by modifying the fixtures in the following manner:

import { test as baseTest, BrowserContextOptions } from '@playwright/test';
import SignUp from '../pages/SignUp';
import fs from 'fs';
import path from 'path';

export * from '@playwright/test';
export const test = baseTest.extend<{}, { workerStorageState: string }>({
    // Using the same storage state for all tests in this worker.
    storageState: ({ workerStorageState }, use) => use(workerStorageState),

    // Authenticating once per test with a test-scoped fixture.
    workerStorageState: [
        async ({ browser }, use) => {
            // Utilizing parallelIndex as a unique identifier for each worker.
            const id = test.info().parallelIndex;
            const fileName = path.resolve(test.info().project.outputDir, `.auth/${id}.json`);

            const contextOptions: BrowserContextOptions = {
                storageState: undefined,
            };
            // Ensure authentication in a clean environment by unsetting storage state.
            const context = await browser.newContext(contextOptions);
            const page = await context.newPage();

            // Generating fake user data and performing signUp
            const signUp = new SignUp(page);
            // Signing up a new user
            await signUp.SignUp();

            // Saving the new storage state for this test.
            await context.storageState({ path: fileName });

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Checking if a value exists in an array using *ngIf

I'm just starting to learn Ionic and Angular, so I'm hoping someone can provide some guidance. Here is the data I have: "messages" : [ { "sender" : "24", "name" : "James", "datetime" : ISODate("2019- ...

JavaScript error occurs when the max old space size is enlarged, resulting in an invalid size

Encountering an error while attempting to compute a sha256 hash of a large buffer (~300 MB) using the hash.js library: # # Fatal error in , line 0 # Fatal JavaScript invalid size error 169220804 # # # #FailureMessage Object: 0x7ffd6dc623c0 1: 0xbe6ad1 [/ ...

Utilizing next-redux-wrapper within the getServerSideProps function in Next.js allows for seamless

When trying to call an action function in getServerSideProps using TypeScript, I encountered some challenges. In JavaScript, it is straightforward: import { wrapper } from "Redux/store"; import { getVideo } from "Redux/Actions/videoAction&qu ...

Error 409 in Telegraf: Conflict arises due to termination caused by setWebhook request in Telegram

Below is the bot code snippet: export class TelegramBot { private bot: Telegraf<Scenes.SceneContext>; private isInitialized: boolean = false; constructor() { this.bot = new Telegraf(TELEGRAM_TOKEN); } initialize() { try { th ...

Discover how TypeScript's strictNullChecks feature can help you identify null values with ease in your functions

Since Javascript often requires me to check if a value is `!= null && != ''`, I decided to create a function that checks for empty values: const isEmpty = (variable: any, allowEmptyString?: boolean): boolean => { return variable == null | ...

Issues with the rating plugin functionality in Ionic 3

After following the instructions in this tutorial: http://ionicframework.com/docs/native/app-rate/ Even though I implemented the second method, I encountered the following error: Uncaught (in promise): TypeError: Cannot read property 'split' ...

Discover the method of extracting information from an object and utilizing it to populate a linechart component

Object Name: Upon calling this.state.lineChartData, an object is returned (refer to the image attached). The structure of the data object is as follows: data: (5) [{…}, {…}, {…}, {…}, {…}, datasets: Array(0), labels: Array(0)] In the image p ...

Creating a nrwl/nx workspace with Angular Universal and encountering a typing problem in Cypress configuration

TL;DR When I run yarn webpack:server, I encounter the error message Cannot find name 'cy'. Example repository: Branch displaying error Error Explanation Hello, I am currently in the process of setting up a minimal viable product project to ...

Tips for incorporating a mesh into Forge Viewer v6 with Typescript

Is there a way to add meshes to Forge Viewer v6 using Type script? I've tried various methods that worked with v4, but I'm encountering issues now. private wallGeometry: THREE.BoxBufferGeometry; drawWalls() { ...

Error message: Conflicting type declarations across multiple files

I am facing a challenge with my TypeScript 'snippets' project. It seems that multiple .ts files contain type names (like Foo) that are the same. //file-a.ts type Foo = { } //file-b.ts type Foo = { } When attempting to compile, I encounter ...

Utilize devextreme for uploading files

Currently, I am trying to implement an upload document feature using Dev-Extreme, but I keep encountering an error https://i.sstatic.net/dLxWx.png onFileUpload(event){ this.file = event.target.files[0] } <dxi-column [showInColumnChooser]="fa ...

Empty array being returned by Mongoose after calling the populate() function

I've been struggling for the past 3-4 hours, banging my head against the wall and scouring countless articles here on StackOverflow, but I just can't seem to get my response to populate an array correctly. I'm working with Express.js, Typesc ...

A Comprehensive Guide to Fetching Superset Dashboard Thumbnail Image in an Angular Application Through API Integration

Greetings to the wonderful Stack Overflow community! I have been working diligently on incorporating Superset into my Angular application, but I have encountered a hurdle when attempting to retrieve the thumbnail image of a specific Superset dashboard. Cu ...

Error: Jest + Typescript does not recognize the "describe" function

When setting up Jest with ts-jest, I encountered the error "ReferenceError: describe is not defined" during runtime. Check out this minimal example for more information: https://github.com/PFight/jest-ts-describe-not-defined-problem I'm not sure what ...

The ts-jest node package's spyOn method fails to match the specified overload

Currently, I'm exploring the usage of Jest alongside ts-jest for writing unit tests for a nodeJS server. My setup is quite similar to the snippet below: impl.ts export const dependency = () => {} index.ts import { dependency } from './impl.t ...

Using *ngIf can lead to a never-ending cycle that never gets resolved

I am currently working on a project using Angular and I need to conditionally display a form based on certain values. I have successfully tested the backend route using Postman and everything is functioning correctly. Here is a snippet of my code: Block ...

Issue with the animation on Material UI accordion component not functioning as expected

While working on an accordion project using Material UI, I discovered an issue. When the Accordion is directly placed in the file's return statement, it functions properly with smooth animations. However, when I create a sub-component and return it, t ...

What is the reason for Yarn to generate subsequent requests while installing a particular package?

After setting up verdaccio and publishing a private package to it, I configured the yarn registry to send requests to the verdaccio proxy server. However, when making requests to the proxy server, yarn is also sending additional requests to the yarnpkg s ...

Using TypeScript, take advantage of optional chaining in conjunction with object destructuring

After updating typescript to version 3.7.4, I find myself trying to modify my code. My code is straightforward: interface Test event: { queryStringParameters: { [name: string]: string } | null; } } const test:Test = (event) => { // const { n ...

What is the best way to utilize the object within the map function?

I have a situation where I am using a typescript code repeatedly and I want to find a way to make it more efficient by reusing the code through assigning it to a variable. An example of this is defining an arrow function within the map function to return a ...