嘿, 今天我想谈谈 Fixtures,如果您要使用 Playwright 并且想要在测试之间共享数据或创建自定义执行,那么它是一个重要的朋友。 让我们从一个简单的例子开始。 test('should win the player "X"', async ({ page }) => { await page.goto("/"); await page.locator("button:nth-child(1)").click(); await page.locator("button:nth-child(5)").click(); await page.locator("button:nth-child(6)").click(); await page.locator("button:nth-child(7)").click(); await page.locator("button:nth-child(3)").click(); await page.locator("button:nth-child(9)").click(); await page.locator("button:nth-child(2)").click(); const winnerParagraph = await page.getByText(/winner/i); await expect(winnerParagraph).toContainText("X"); }); 想象一下,您想要提取数组中按钮的所有索引以复制此测试并减少所有这些单击命令以进行更短的测试。 因此,在引入夹具功能之前的第一个重构可能是这样的。 test('should win the player "X"', async ({ page }) => { const playerXWinMoves = [1, 5, 6, 7, 3, 9, 2]; for (const move of playerXWinMoves) { await page.locator(`button:nth-child(${move})`).click(); } const winnerParagraph = await page.getByText(/winner/i); await expect(winnerParagraph).toContainText("X"); }); 正如您所注意到的,重现玩家移动的所有步骤都包含在 变量中。测试很简洁,但最重要的是,所有操作都在一个变量中。现在是介绍固定装置的时候了。 playerXWinMoves 在继续之前,让我花一些话来描述什么是固定装置。 什么是固定装置 测试夹具用于为每个测试建立一个环境,为测试提供它需要的一切,除此之外别无其他。测试夹具在测试之间是隔离的。使用固定装置,您可以根据测试的含义而不是标准设置对测试进行分组。 在这个定义之后,你可以认为 fixtures 可以被 before/after hooks 代替,但是 fixtures 比这些 hooks 有几个优点: Fixtures 将 setup 和 teardown 在同一个地方,使其更容易编写。 封装 夹具可在测试文件之间 - 您可以定义一次并在所有测试中使用它们。这就是 Playwright 的内置 固定装置的工作原理。 重复使用 page 固定装置是 ——您可以根据需要定义任意数量的固定装置,Playwright Test 将仅设置您的测试所需的固定装置,而不会设置其他任何固定装置。 按需提供的 夹具是 ——它们可以相互依赖以提供复杂的行为。 可组合的 固定装置 。测试可以使用夹具的任意组合来定制所需的精确环境,而不会影响其他测试。 灵活 夹具简化了 。您不再需要将测试包装在设置环境的 中,而是可以自由地按测试的含义对测试进行分组。 分组 describe 太棒了,在这个无聊的理论部分之后,是时候动手操作 Playwright 中的固定装置了。 在开始解释之前,我想从最终结果开始。 import { expect, test as base } from "@playwright/test"; type TestFixtures = { playerXWinMoves: [number, number, number, number, number, number, number]; }; const test = base.extend<TestFixtures>({ playerXWinMoves: async ({}, use) => { await use([1, 5, 6, 7, 3, 9, 2]); }, }); test('should win the player "X"', async ({ page, playerXWinMoves }) => { for (const move of playerXWinMoves) { await page.locator(`button:nth-child(${move})`).click(); } const winnerParagraph = await page.getByText(/winner/i); await expect(winnerParagraph).toContainText("X"); }); 如您所见,要构建我们的夹具,您必须扩展 Playwright 公开的测试对象。在这个函数中,您可以创建一个代表您的灯具的对象。在这种情况下,我添加了 属性来共享重现玩家 X 获胜的步骤。此外,因为我喜欢使用 Typescript,所以我添加了 类型来描述我的设备。请务必注意,在夹具内部,您必须使用 方法来设置夹具的值。 playerXWinMoves TestFixtures use 好,继续,现在让我们看一下测试。您会注意到,您可以直接从传递给测试的对象中获取 fixture。现在,如果您删除以前的变量并使用参数中的新变量,您将使用夹具创建 Playwright 的第一个测试。 playerXWinMoves 太好了,我希望你能理解这个特性的不可思议的力量,以及它如何帮助你使你的测试更具可读性,或者将一些在许多测试中有用的数据汇集在一起。 但在结束之前,让我再留一点。使用固定装置,您还可以覆盖由 Playwright 直接公开的对象。例如,您可以覆盖页面对象,而不是创建一个 钩子来导航到主页,您可以覆盖页面并将此步骤添加到固定装置中,这样每个测试在执行之前都会运行导航步骤到主页。 beforeEach 我们该怎么做?就这么简单。 const test = base.extend<TestFixtures>({ page: async ({ baseURL, page }, use) => { baseURL && (await page.goto(baseURL)); await use(page); }, }); 这样做,现在每个测试在开始执行时都会转到 baseURL,然后运行所有代码。难以置信不?现在,您可以删除测试文件中的 挂钩并重新运行测试以检查结果。 beforeEach 好吧,这就是所有的人! 今天,您了解了 Playwright 装置的工作原理以及如何构建装置。 我希望您喜欢这篇文章,如果您有任何疑问,请随时与我联系;我很乐意帮助你。 再见 再见👋 ps 你可以 在这里 查看本文的代码