You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将基于Jest的用户旅程式测试迁移至使用Fixtures的@playwright/test?

Hey there! Let's walk through migrating your Playwright + Jest setup to @playwright/test with fixtures, and tackle each of your questions clearly.

1. Migrating Your Test Architecture to @playwright/test + Fixtures

Playwright's fixtures are built to replace custom setup/teardown hooks like beforeAll/afterAll with reusable, maintainable dependencies. Here's how to map your existing workflow:

First, create a custom fixture file (e.g., fixtures.js) to wrap your suite setup/teardown logic:

const { test: base } = require('@playwright/test');

// Extend the base test with our custom fixtures
exports.test = base.extend({
  // We'll handle parameterization here (more on that in question 2)
  userConfig: [{ isPrime: false, paymentOptions: ["paypal", "visa"] }, { option: true }],

  // Suite-scoped fixture: runs once per test suite, shares state across all tests in the suite
  suiteContext: [async ({ browser, browserOptions, userConfig }, use) => {
    // 1. Replicate your setupSuite logic
    const browserInstance = await base.chromium.launch({ ...browserOptions });
    const page = await browserInstance.newPage();

    // Enable built-in tracing (replaces your custom trace reporter)
    await page.context().tracing.start({ screenshots: true, snapshots: true });

    // Navigate to base URL (configure this in playwright.config.js for cleaner code)
    await page.goto('/');

    // Handle cookie banner
    await page.click('[data-testid="cookie-accept"]');

    // Create user from config
    const user = await createUser(userConfig); // Your existing user creation function

    // Log in the user (move this here to make it part of the suite setup)
    await page.fill(".login-username-input", user.username);
    await page.fill(".login-password-input", user.password);
    await page.click(".login-submit-button");

    // Pass the context (browser, page, user) to all tests in the suite
    await use({ browser: browserInstance, page, user });

    // 2. Replicate your teardownSuite logic
    await page.context().tracing.stop({ path: `trace-${user.username}.zip` });
    await browserInstance.close();
    await deleteUser(user); // Your existing user deletion function
  }, { scope: 'suite' }], // Explicitly set scope to suite
});
exports.expect = base.expect;

Then rewrite your test file to use this fixture:

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

test.describe("Successful Order", () => {
  // Tests pull shared context from the suiteContext fixture
  test("search for toothbrush with suggestions", async ({ suiteContext }) => {
    const { page } = suiteContext;
    
    await page.fill(".search-input", "tooth");
    await page.click("text='toothbrush'");
    
    // Assertions
    await expect(page.locator(".search-results")).toBeVisible();
  });

  test("click on first item and add to cart", async ({ suiteContext }) => {
    const { page } = suiteContext;
    
    await page.locator(".search-result-item").first().click();
    await page.click("#add-to-cart-button");
    
    await expect(page.locator("#cart-count")).toHaveText("1");
  });

  // Add your remaining test blocks here (go back to add second item, checkout, etc.)
});

2. Migrating setupSuite/teardownSuite with Parameterized Fixtures

Yes, Playwright fully supports parameterized fixtures! Here's how to pass userConfig to your setup logic:

  • In your fixture definition, we added a userConfig fixture with a default value.
  • To override it for a specific test suite, use test.use() inside your test.describe block:
    test.describe("Successful Order", () => {
      // Override userConfig for this entire suite
      test.use({
        userConfig: { isPrime: true, paymentOptions: ["visa"] }
      });
    
      // Tests here will use this custom userConfig
    });
    
  • You can even override it for individual tests if needed:
    test("check prime-only discount", async ({ suiteContext }) => {
      // This test uses the suite's userConfig, but you could override it here too
    });
    

The suiteContext fixture automatically receives the userConfig value, so your setup logic can adapt dynamically.

3. Building Test Structure for Full User Journeys

You don't have to sacrifice readability or logical splitting! Here are two key strategies:

a. Use test.step() for granular logic blocks

Wrap individual actions in test.step() to make your test flow clear, and get better failure reporting (Playwright will show exactly which step failed):

test("go to cart and pay", async ({ suiteContext }) => {
  const { page, user } = suiteContext;

  await test.step("Navigate to cart", async () => {
    await page.click("#cart-icon");
  });

  await test.step("Select payment method", async () => {
    await page.selectOption("#payment-method", user.paymentOptions[0]);
  });

  await test.step("Complete checkout", async () => {
    await page.click("#place-order-button");
  });

  await expect(page.locator(".order-confirmation")).toBeVisible();
});

b. Extract reusable actions into utility functions

If you have repeated steps (like adding items to cart), move them to a utility file:

// utils/amazon.js
exports.addItemToCart = async (page, itemLocator) => {
  await page.click(itemLocator);
  await page.click("#add-to-cart-button");
  await expect(page.locator("#cart-count")).toHaveText((current) => parseInt(current) + 1);
};

Then import and use it in tests:

const { addItemToCart } = require('./utils/amazon');

test("click on second item and add to cart", async ({ suiteContext }) => {
  const { page } = suiteContext;
  await addItemToCart(page, ".search-result-item:nth-child(2)");
});

This keeps your test files focused on the journey flow, not repetitive actions.

4. Sharing a Page Instance Across Tests

The key here is using suite-scoped fixtures. By default, Playwright creates a new page for each test, but setting the fixture's scope to suite (as we did in the suiteContext fixture) tells Playwright to create the context once for the entire test suite.

All tests in the describe block will share the same page instance, and Playwright will handle video recording and tracing correctly—you'll get a single trace/video for the entire suite (or per-test if you configure it that way in playwright.config.js). This is a supported, safe practice, unlike manual page creation which breaks Playwright's built-in tools.

5. Are User Journey Tests a Poor Fit for Playwright's Fixtures?

Absolutely not! Playwright's fixtures are not just for data-driven testing—they're designed to provide any kind of test dependency, including persistent state for user journeys.

The confusion might come from seeing data-driven test examples, but suite-scoped fixtures are perfect for user journeys because:

  • They encapsulate repetitive setup (login, user creation) so you don't repeat code across journeys.
  • They maintain state across tests (like a logged-in session, items in cart) without manual hacks.
  • They integrate seamlessly with Playwright's debugging tools (tracing, video, screenshots) which are critical for troubleshooting long journeys.

Your user journey tests are totally valid, and fixtures will make them more maintainable in the long run.


内容的提问来源于stack exchange,提问作者ysfaran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 23:17:42