如何通过 Playwright 模拟特定响应的 HTTP 网络请求

如何通过 Playwright 模拟特定响应的 HTTP 网络请求

· 935 词 · 5 分钟 读完 playwright基础 翻译

我最近遇到一个场景,我想检查一个 UI 元素,但 UI 元素中的数据是一个计数器,而我套件中的其他测试会影响这个计数。我看到有两种方法可以解决这个问题。一种是拦截网络流量并抓取这个值,然后对这个值进行断言,另一种方法是拦截并 mock(自己设置 1 个假的值) 一个我传入的值作为响应。

在本文中,我将演示一个简单的拦截和模拟网络请求的场景。

首先,我们创建一个名为count的变量,并将其设置为 100。这个值可以是任何数字,因为它将被传入测试名称、mockMessageCount 函数,并在断言中使用。

在这个测试中,我在 beforeEach 方法中有很多操作,理想情况下,我会将很多这些操作抽象到一个页面对象中,使测试更加简洁。这个测试假设在test部分开始时你已经登录。在 beforeEach 中,我还调用了mockMessageCount(page, count)方法。此代码调用了测试规范底部列出的异步函数。这个函数可以很容易地存在于不同的文件中,通过从它自己的文件中导出函数并在其他测试用例中导入。下面的代码使用 route 类,对于以"/message/count"结尾的任何 URL,我们将直接 mock 这个接口的返回值。我通过这个接口https://automationintesting.online/message/count mock 返回值。这是不需要身份验证的,所以你可以点击并查看当前的计数。

export async function mockMessageCount(page, messageCount) {
  await page.route("**/message/count", (route) =>
    route.fulfill({
      status: 200,
      body: JSON.stringify({ count: messageCount }),
    })
  );
}

由于我们在 mockMessageCount 中传入了 100 作为计数,因此在 Playwright 测试用例中 mock 了100 这个返回。完整的测试如下所示。

import { test, expect, selectors } from "@playwright/test";

test.describe("/admin 检查", async () => {
  let count = "100";

  test.beforeEach(async ({ page }) => {
    selectors.setTestIdAttribute("data-testid");

    // 这调用了一个在此页面底部存在的异步函数,它接受页面实例和一个数字
    await mockMessageCount(page, count);
    await page.goto("https://automationintesting.online/");
    await page.getByRole("button", { name: "Let me hack!" }).click();
    await page.getByRole("link", { name: "Admin panel" }).click();
    await page.getByTestId("username").click();
    await page.getByTestId("username").fill("admin");
    await page.getByTestId("password").click();
    await page.getByTestId("password").fill("password");
    await page.getByTestId("submit").click();
  });

  test(`验证消息计数为${count}`, async ({ page }) => {
    await expect(page.getByRole("link", { name: "Logout" })).toHaveText(
      "Logout"
    );

    const messageCountSpan = page
      .locator('[href*="#/admin/messages"]')
      .locator("span");

    await expect(messageCountSpan).toHaveText(`${count}`);
  });
});

// 这个函数使用route类,拦截服务器发送的内容,并用我们提供的响应进行满足(模拟!)
export async function mockMessageCount(page, messageCount) {
  await page.route("**/message/count", (route) =>
    route.fulfill({
      status: 200,
      body: JSON.stringify({ count: messageCount }),
    })
  );
}

Playwright 文档链接

查看文档将帮助你更深入地了解 page.route 类的所有可能性。下面是一个简要总结。

abort() 终止 route 的请求。

continue() 继续 route 的请求,并可选择性地进行覆盖。

fallback() 当多个路由匹配给定模式时,它们按照注册顺序的相反顺序运行。这样,最后注册的路由总是可以覆盖所有先前的路由。在下面的示例中,请求将首先由最底层的处理程序处理,然后它会回退到上一个,最后由第一个注册的路由终止。

fetch() 执行请求并获取结果,而不进行满足,以便可以修改响应然后进行满足。

fulfill() 使用给定的响应满足 route 的请求。


示例中的代码可以在这个仓库中找到。代码示例

来源

URL Source

发布时间: 2023-04-24