How to share a variable's value between parametrized and non parametrized test in Playwright with Typescript?

171 Views Asked by At

As in the title. Here's where I came from:

  1. Sharing variable's value worked fine before I introduced parametrization.
imports { ... } ...

let myVariable: string;

test.describe.configure({mode: serial})
test.beforeEach(async ({page, variousPOJs})) => {
    visit main page, etc.
}

test(`scenario for case 1`, async ({
}) => {
    myVariable = "123"
})

test(`scenario for case 2`, async ({
}) => {
    console.log(myVariable) ==> outputs "123" 
})
  1. After parametrization:
imports { ... } ...

let myVariable: string;

test.describe.configure({mode: serial})
test.beforeEach(async ({page, variousPOJs})) => {
    visit main page, etc.
}

const cases = [{nr: 1, title: "a", objName: "normal"}, {nr: 2, title: "b", objName: "updated"}];

for (const case of cases) {
  test(`test for case nr ${case.nr} doing ${case.title}`, async ({
      myVariable = `some value ${case.objName}`;
  })  
}

test(`test for case nr 3 doing c`, async ({
      console.log(myVariable); ==> outputs "undefined"
  })

2 suggestion from chatgpt. First one is useless, the variable defaults to empty value (obviously). The second one seems possible, though untested by me. I wanted to refrain myself from creating something more complex than sharing a variable within the same file, cause the automated test I write it for is super simple. It's just creating a object in the app, fetching its name and updating that name.

import { test, expect } from '@playwright/test';

let categoryName: string;

test.beforeEach(async () => {
  // Inicjalizuj wartość categoryName przed każdym testem
  categoryName = '';
});

for (const tytul of ['test1', 'test2']) {
  test(`Test sparametryzowany - ${tytul}`, async ({ page }) => {
    // Wykonaj operacje specyficzne dla danego scenariusza
    await page.goto('https://www.example.com');

    // Nadpisz wartość categoryName
    categoryName = `Category_${tytul}`;

    // Przykładowa operacja, która wykorzystuje wartość z danej iteracji
    await page.fill('input[name="poleFormularza"]', 'WartośćTestowa');
    await page.click('button[type="submit"]');
    
    // Oczekuj na jakąś operację, możesz dostosować to do swoich potrzeb
    await page.waitForSelector('div.wynik');

    // Sprawdź, czy otrzymany wynik jest poprawny
    const wynik = await page.textContent('div.wynik');
    expect(wynik).toBe('Oczekiwany wynik dla WartośćTestowa');
  });
}

// Test niepoddany parametryzacji, korzystający z nadpisanej wartości categoryName
test('Test bez parametryzacji', async ({ page }) => {
  if (categoryName) {
    console.log(`Używam nadpisanej wartości categoryName w teście bez parametryzacji: ${categoryName}`);
  }

  // Tutaj możesz dodać operacje specyficzne dla tego testu
});
import { Context } from '@playwright/test';

export interface SharedState {
  categoryName: string;
}

export const sharedContext = new Context<SharedState>();

export const setCategoryName = (categoryName: string) => {
  sharedContext.state.categoryName = categoryName;
};

export const getCategoryName = () => {
  return sharedContext.state.categoryName;
};


____
test:

import { test, expect } from '@playwright/test';
import { setCategoryName, getCategoryName } from './sharedState';

test.beforeEach(async ({ context }) => {
  // Inicjalizuj wartość categoryName przed każdym testem
  setCategoryName('');
});

for (const tytul of ['test1', 'test2']) {
  test(`Test sparametryzowany - ${tytul}`, async ({ page }) => {
    // Wykonaj operacje specyficzne dla danego scenariusza
    await page.goto('https://www.example.com');

    // Nadpisz wartość categoryName
    setCategoryName(`Category_${tytul}`);

    // Przykładowa operacja, która wykorzystuje wartość z danej iteracji
    await page.fill('input[name="poleFormularza"]', 'WartośćTestowa');
    await page.click('button[type="submit"]');
    
    // Oczekuj na jakąś operację, możesz dostosować to do swoich potrzeb
    await page.waitForSelector('div.wynik');

    // Sprawdź, czy otrzymany wynik jest poprawny
    const wynik = await page.textContent('div.wynik');
    expect(wynik).toBe('Oczekiwany wynik dla WartośćTestowa');
  });
}

// Test niepoddany parametryzacji, korzystający z nadpisanej wartości categoryName
test('Test bez parametryzacji', async ({ page }) => {
  const categoryName = getCategoryName();

  if (categoryName) {
    console.log(`Używam nadpisanej wartości categoryName w teście bez parametryzacji: ${categoryName}`);
  }

  // Tutaj możesz dodać operacje specyficzne dla tego testu
});
2

There are 2 best solutions below

0
candre On

Some small tweaks on your own suggestion, seem to do the trick:

Beware, case is a reserved name and cannot be used as variable name.

import { test } from "@playwright/test";

const testCases = [
  { nr: 1, title: "a", objName: "normal" },
  { nr: 2, title: "b", objName: "updated" },
];

let myVariable = "hi";

test.describe.configure({ mode: "serial" });

for (const testCase of testCases) {
  test(`test for case nr ${testCase.nr} doing ${testCase.title}`, async () => {
    myVariable = `some value ${testCase.objName}`;
  });
}

test(`test for case nr 3 doing c`, async () => {
  console.log(myVariable);
  // Now logs: "some value updated" - as desired
});

On a general note, sharing variables between tests is sort of bad practice and makes the tests dependant on each other,read som good advices on test isolation in the docs.

0
pbaranski On

Here is resolution of your problem:

import { test, expect } from '@playwright/test';

test.describe.configure({ mode: 'serial' });
test.describe('test suite', () => {
  let myVariable: string;
  const cases = [
    { nr: 1, title: 'a', objName: 'normal' },
    { nr: 2, title: 'b', objName: 'updated' },
  ];

  for (const c of cases) {
    test(`test for case nr ${c.nr} doing ${c.title}`, async () => {
      myVariable = `some value ${c.objName}`;
    });
  }

  test(`scenario for case 3`, async ({}) => {
    console.log('Variable: ', myVariable);
    expect(myVariable).toBe('some value updated');
  });
});

Few things to mention:

  1. Add describe to tests like this so you can easily run serial test together i.e. in VSCode
  2. Final value for scenario for last test will be last value set in parametrised test

Hope that helps, comment if more explanation needed.