0

I am learning playwright and it highly recommends to use customer facing selectors...
so that rises a question what is the best approach for localisation testing.

I am using https://practice.automationbro.com/ to practice and unfortunately it does not have localisation so my example is just theoretical now.

My page object looks like this

export default class HomePage {
  page: Page;
  getStarter: Locator;
  headingText: Locator;

  constructor(page: Page) {
    this.page = page;
    this.getStarter = page.locator("#get-started");
    this.headingText = page.locator("text=Think different. Make different.");
  }

  public async navigate() {
    await this.page.goto("https://practice.automationbro.com");
  }

  public async assertHeadingTextIsVisible(){
    await expect(this.headingText).toBeVisible();
  }

[...]

And i am thinking to write a test file like this

test.describe("Home (EN)", () => {
  let homePage: HomePage;

    test.use({
      locale: 'en-GB',
      timezoneId: 'Europe/London',
    });

    test("Home page verify heading text", async ({ page }) => {
     homePage = new HomePage(page)

     await homePage.navigate()
     await homePage.assertHeadingTextIsVisible(<headingtext GB>)
  });
})

test.describe("Home (BE)", () => {
  let homePage: HomePage;

    test.use({
      locale: 'nl-BE',
      timezoneId: 'Europe/Brussels',
    });

    test("Home page verify heading text", async ({ page }) => {
     homePage = new HomePage(page)

     await homePage.navigate()
     await homePage.assertHeadingTextIsVisible(<headingtext BE>)
  });
})

How to define this.headingText = page.locator("text=Think different. Make different.") locator in HomePage object?

2 Answers2

1

If you want to run the same test for several locales, you could parameterize it by iterating over a list with all locale specific parameters:

Putting all locale specific parameters in a separate file, localesInTest.ts

export interface LocaleInTest {
  locale: string,
  timezoneId: string,
  selectors: {
    getStarted: string
    headingText: string
  }
}

const localesInTest: LocaleInTest[] = [
  {
    locale: 'en-GB',
    timezoneId: 'Europe/London',
    selectors: {
      getStarted: '#get-started',
      headingText: 'text=Think different. Make different.'
    }
  },
  {
    locale: 'nl-BE',
    timezoneId: 'Europe/Brussels',
    selectors: {
      getStarted: '-nl locator here-',
      headingText: '-nl locator here-'
    }
  }
];

// Adding localeInTest interface to class constructor Page object:

export default class HomePage {
  page: Page;
  getStarter: Locator;
  headingText: Locator;
  localeInTest: LocaleInTest;

  constructor(page: Page, localeInTest: LocaleInTest) {
    this.page = page;
    this.localeInTest = localeInTest
    this.getStarter = page.locator(localeInTest.selectors.getStarted);
    this.headingText = page.locator(localeInTest.selectors.headingText);
  }

  public async navigate() {
    await this.page.goto('https://practice.automationbro.com');
  }

  public async assertHeadingTextIsVisible() {
    await expect(this.headingText).toBeVisible();
  }
}

And your test would be looking something like this:

import { LocaleInTest } from XX;

// Iterate over locales defined in localesInTest.ts
for (const localeInTest of localesInTest) {

  test.describe(`Home - ${localeInTest.locale}`, () => {

    test.use({
      locale: localeInTest.locale,
      timezoneId: localeInTest.timezoneId
    });

    test(`Home page verify heading text (${localeInTest.locale})`, async ({ page }) => {

      // Using specific test parameters when creating new HomePage instance:
      const homePage = new HomePage(page, localeInTest);

      await homePage.navigate();
      await homePage.assertHeadingTextIsVisible();
    });
  });
}
candre
  • 593
  • 3
  • 8
  • Very detailed and helpful answer thank you, however what is the use of 'interface' here? All the way down from page object to test where we can simply use an array in its place and iterate over it in test. – Vishal Aggarwal Jun 29 '23 at 10:07
  • Just trying to understand it. – Vishal Aggarwal Jun 29 '23 at 10:07
  • 1
    @VishalAggarwal The asker of the question used a page object model in their example. Secondly, I find it more readable and flexible as you can pass more than just strings into the parameterization, for example more complex objects. But you are right, if its just a list of selector strings, using a csv might suffice . – candre Jun 29 '23 at 20:13
0

Alternatively you may also parameterize tests via CSV file:

The Playwright test-runner runs in Node.js, this means you can directly read files from the file system and parse them with your preferred CSV library.

See for example this CSV file below:

`"test_case","some_value","some_other_value"
"value 1","value 11","foobar1"
"value 2","value 22","foobar21"
"value 3","value 33","foobar321"
"value 4","value 44","foobar4321"

Based on this we can create some tests by using the csv-parse library from NPM:

import fs from 'fs';
import path from 'path';
import { test } from '@playwright/test';
import { parse } from 'csv-parse/sync';

const records = parse(fs.readFileSync(path.join(__dirname, 'input.csv')), {
  columns: true,
  skip_empty_lines: true
});

for (const record of records) {
  test(`foo: ${record.test_case}`, async ({ page }) => {
    console.log(record.test_case, record.some_value, record.some_other_value);
  });
}
Vishal Aggarwal
  • 1,929
  • 1
  • 13
  • 23