Search code examples
playwrightplaywright-test

Playwright configuration: POM fixtures for projects


I need to configure Playwright to use different POM fixtures for different project settings.

All examples I find configure the POM while extending the base test. This works, but this way Playwright would use the same POM fixture for all projects.

import { test as base } from '@playwright/test';

type TestOptions = {
  productDetailPom: ProductDetailPom
};

export const test = base.extend<TestOptions>({
  productDetailPom: async ({ browser }, use) => {   
     await use(await ProductDetailPom.create(browser, 'url'));
  },
});

What I need are different POMs for each configured project. Is there a way to create a POM instance with the browser or page fixture for each project in the config?

// playwright.config.ts
const config: PlaywrightTestConfig<TestOptions> = {
  ...
  projects: [
    {
      name: 'proj1',
      use: {
        productDetailPom: new ProductDetailPom1(browser, 'url1') // POM instance 1
      }
    },
    {
      name: 'proj2',
      use: {
        productDetailPom: new ProductDetailPom2(browser, 'url2') // POM instance 2
      }
    }
  ],
};

Solution

  • I found no way to construct POMs in the config, but a workaround. Here is what I came up with. Please tell me if you have a better solution.

    In short: The POM instances are created not in the config, but later. For instantiation I use a factory, which can be the same for all projects. Only the data fed into the factory differ per project.

    In the config I add the data I need for construction: the POM class itself and data that will get passed to the constructor. Those data can be different in each project.

    // playwright.config.ts
    const config: PlaywrightTestConfig<TestOptions> = {
      ...
      projects: [
        {
          name: 'proj1',
          use: {
            productDetailPomConstr: [ProductDetailPom1, 'url1']
          },
        },
        {
          name: 'proj2',
          use: {
            productDetailPomConstr: [ProductDetailPom2, 'url2']
          }
        }
      ]
    };
    

    For creating the instance of the POM I use a factory, which is the same for all projects and because of this can be added by extending the base test. This is where I get the browser instance from (you could also get all other fixtures like page).

    import { test as base } from '@playwright/test';
    
    type TestOptions = {
      pomFactory: PomFactory,
      productDetailPomConstr: [typeof ProductDetailPom, Record<string, any>]
    };
    
    export const test = base.extend<TestOptions>({
      pomFactory: async ({ browser }, use) => {
        const pomFactory = new PomFactory(browser);
        await use(pomFactory);
      },
      productDetailPomConstr: [null, { option: true }],
    });
    

    In the test I can get both fixtures, factory and PomConstruction data, and instantiate my POM with them.

    test('someTest', async ({pomFactory, productDetailPomConstr}) => {
      const pdPom = await pomFactory.create<ProductDetailPom>(productDetailPomConstr);
    });
    

    Maybe this helps someone.