0

I want to compose fixtures. The first fixture should always be available (think of it as base class). second fixture will vary in different test files (think of it as derived class) I tried following code and it's working as I was expecting. Is this ok to follow this approach or any better option available?

//baseFixture.js
import { test as base} from '@playwright/test';
interface MyFixtures {
  fixture1: string;
}

export const test = base.extend<MyFixtures>({
  fixture1: "fixture-one"
}, );

//derivedFixture.js

import {test as test1} from 'baseFixture'
interface MyFixtures2 {
  fixture2: string;
}

export const test = test1.extend<MyFixtures2>({
  fixture2: "fixture-two"
}, );


//in test_file.js

import {test} from 'derivedFixture'

  test('should allow me use composed fixture', async ({ page, fixture1, fixture2 }) => {
     console.log(`from first fixture ${fixture1}`)
     console.log(`from second fixture ${fixture2}`)
  });

2 Answers 2

3

Seems to me that you are using fixtures like POMs and you are overengineering tests. If it works for you and depending on what you want, then use it. If my assumption is correct instead of passing fixtures to another fixture pass POMs and you can even perform steps here to get that page into certain state and here is example from playwright page:

// my-test.js
const base = require('@playwright/test');
const { TodoPage } = require('./todo-page');
const { SettingsPage } = require('./settings-page');

// Extend base test by providing "todoPage" and "settingsPage".
// This new "test" can be used in multiple test files, and each of them will get the fixtures.
exports.test = base.test.extend({
  todoPage: async ({ page }, use) => {
    // Set up the fixture.
    const todoPage = new TodoPage(page);
    await todoPage.goto();
    await todoPage.addToDo('item1');
    await todoPage.addToDo('item2');

    // Use the fixture value in the test.
    await use(todoPage);

    // Clean up the fixture.
    await todoPage.removeAll();
  },

  settingsPage: async ({ page }, use) => {
    await use(new SettingsPage(page));
  },
});
exports.expect = base.expect;

Then in your test simply pass {todoPage} or {settingsPage} or both:

const { test, expect } = require('./my-test');

test.beforeEach(async ({ settingsPage }) => {
  await settingsPage.switchToDarkMode();
});

test('basic test', async ({ todoPage, page }) => {
  await todoPage.addToDo('something nice');
  await expect(page.locator('.todo-item')).toContainText(['something nice']);
});

Also you can chain your fixtures here and reuse them, for eg. you could pass todoPage to settingsPage fixture:

  settingsPage: async ({ todoPage}, use) => {
    await use(new SettingsPage(page));
  },

This way everything in todoPage will be executed then settingsPage and this is what you pass to your test, and I guess this is what you were trying to achive.

Sign up to request clarification or add additional context in comments.

Comments

1

My approach is to use the base fixture as a dependent fixture in a derivative fixture:

import { test as base } from "@playwright/test"
interface MyFixtures1 {
    fixture1: string
}

export const testBase = base.extend<{}, MyFixtures1>({
    fixture1: [
        async ({}, use) => {
            console.log("fixture1 setup once per worker")
            use("one")
            console.log("fixture1 teardown once per worker")
        },
        { scope: "worker" }
    ]
})

interface MyFixtures2 {
    fixture2: string
}

export const test = testBase.extend<MyFixtures2>({
    fixture2: async ({ fixture1 }, use) => {
        console.log("fixture2 setup for each test")
        use(`two-${fixture1}`)
        console.log("fixture2 teardown for each test")
    },
})

test("should allow me use composed fixture", async ({ fixture1, fixture2 }) => {
    console.log(`from first fixture ${fixture1}`)
    console.log(`from second fixture ${fixture2}`)
})

test("should base", async ({ fixture1 }) => {
    console.log(`from first fixture ${fixture1}`)
})

test("should derived", async ({ fixture2 }) => {
    console.log(`from second fixture ${fixture2}`)
})

More info about how to use fixtures in docs

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.