跳至主要内容

拦截服务

wdio-intercept-service 是一个第三方包,更多信息请参见GitHub | npm

🕸 在webdriver.io中捕获和断言 HTTP ajax 调用

Tests Join the chat on Discord

这是一个用于webdriver.io的插件。如果您还不知道它,请查看一下,它非常酷。

虽然 selenium 和 webdriver 用于 e2e 尤其是 UI 测试,但您可能希望评估客户端代码发出的 HTTP 请求(例如,当您没有即时的 UI 反馈时,例如在指标或跟踪调用中)。使用 wdio-intercept-service,您可以拦截由某些用户操作(例如,按钮按下等)发起的 ajax HTTP 调用,并在稍后对请求和相应的响应进行断言。

不过有一个问题:您无法拦截在页面加载时发起的 HTTP 调用(如大多数 SPA 中那样),因为它需要一些设置工作,而这些工作只能在页面加载后完成(由于 selenium 的限制)。**这意味着您只能捕获在测试内部发起的请求。**如果您对此感到满意,此插件可能适合您,因此请继续阅读。

先决条件

  • webdriver.io v5.x 或更高版本。

注意!如果您仍在使用 webdriver.io v4,请使用此插件的 v2.x 分支!

安装

npm install wdio-intercept-service -D

用法

与 WebDriver CLI 一起使用

它应该像将 wdio-intercept-service 添加到您的 wdio.conf.js 一样简单

exports.config = {
// ...
services: ['intercept']
// ...
};

然后您就完成了。

与 WebDriver 独立版一起使用

当使用 WebdriverIO 独立版时,需要手动调用 beforebeforeTest / beforeScenario 函数。

import { remote } from 'webdriverio';
import WebdriverAjax from 'wdio-intercept-service'

const WDIO_OPTIONS = {
port: 9515,
path: '/',
capabilities: {
browserName: 'chrome'
},
}

let browser;
const interceptServiceLauncher = WebdriverAjax();

beforeAll(async () => {
browser = await remote(WDIO_OPTIONS)
interceptServiceLauncher.before(null, null, browser)
})

beforeEach(async () => {
interceptServiceLauncher.beforeTest()
})

afterAll(async () => {
await client.deleteSession()
});

describe('', async () => {
... // See example usage
});

初始化后,一些相关函数将添加到您的浏览器命令链中(请参见API)。

快速入门

示例用法

browser.url('http://foo.bar');
browser.setupInterceptor(); // capture ajax calls
browser.expectRequest('GET', '/api/foo', 200); // expect GET request to /api/foo with 200 statusCode
browser.expectRequest('POST', '/api/foo', 400); // expect POST request to /api/foo with 400 statusCode
browser.expectRequest('GET', /\/api\/foo/, 200); // can validate a URL with regex, too
browser.click('#button'); // button that initiates ajax request
browser.pause(1000); // maybe wait a bit until request is finished
browser.assertRequests(); // validate the requests

获取有关请求的详细信息

browser.url('http://foo.bar')
browser.setupInterceptor();
browser.click('#button')
browser.pause(1000);

var request = browser.getRequest(0);
assert.equal(request.method, 'GET');
assert.equal(request.response.headers['content-length'], '42');

支持的浏览器

它应该适用于所有浏览器的一些较新版本。如果它似乎不适用于您的浏览器,请报告问题。

API

查阅 TypeScript 声明文件以获取添加到 WebdriverIO 浏览器对象的自定义命令的完整语法。一般来说,任何将“options”对象作为参数的方法都可以不带该参数来获取默认行为。这些“可选 options”对象后面跟着?: = {},并且描述了每个方法推断出的默认值。

选项说明

此库在发出命令时提供少量配置。此处描述了多个方法使用的配置选项(请参阅每个方法定义以确定特定支持)。

  • orderBy'START' | 'END'):此选项控制拦截器捕获的请求在返回到测试时排序的方式。为了与现有版本的此库保持向后兼容,默认排序为'END',这对应于请求完成的时间。如果将orderBy选项设置为'START',则请求将根据其开始时间排序。
  • includePendingboolean):此选项控制是否返回尚未完成的请求。为了与现有版本的此库保持向后兼容,默认值为false,并且仅返回已完成的请求。

browser.setupInterceptor()

捕获浏览器中的 ajax 调用。您始终必须调用 setup 函数才能在以后评估请求。

browser.disableInterceptor()

阻止进一步捕获浏览器中的 ajax 调用。所有捕获的请求信息都将被删除。大多数用户不需要禁用拦截器,但如果测试特别长时间运行或超过会话存储容量,则禁用拦截器可能会有所帮助。

browser.excludeUrls(urlRegexes: (string | RegExp)[])

排除来自某些 url 的请求不被记录。它接受字符串或正则表达式的数组。在写入存储之前,针对每个字符串或正则表达式测试请求的 url。如果匹配,则不会将请求写入存储。与 disableInterceptor 一样,如果遇到会话存储超过容量的问题,这可能会有所帮助。

browser.expectRequest(method: string, url: string, statusCode: number)

对将在测试期间发起的 ajax 请求进行预期。可以(并且应该)进行链接。预期的顺序应与正在发出的请求的顺序相对应。

  • methodString):预期的 http 方法。可以是xhr.open()作为第一个参数接受的任何内容。
  • urlString|RegExp):请求中调用的确切 URL,作为字符串或 RegExp 进行匹配
  • statusCodeNumber):响应的预期状态码

browser.getExpectations()

辅助方法。返回您到目前为止做出的所有预期。

browser.resetExpectations()

辅助方法。重置您到目前为止做出的所有预期。

browser.assertRequests({ orderBy?: 'START' | 'END' }?: = {})

当所有预期的 ajax 请求完成后,调用此方法。它将预期与实际发出的请求进行比较,并断言以下内容

  • 发出的请求数量
  • 请求的顺序
  • 对于每个发出的请求,方法、URL 和 statusCode 应匹配
  • options 对象默认为{ orderBy: 'END' },即请求完成时,以与 v4.1.10 及更早版本的行为保持一致。当orderBy选项设置为'START'时,请求将按页面发起的时间排序。

browser.assertExpectedRequestsOnly({ inOrder?: boolean, orderBy?: 'START' | 'END' }?: = {})

类似于browser.assertRequests,但仅验证您在expectRequest指令中指定的请求,而无需映射可能围绕该请求发生的全部网络请求。如果inOrder选项为true(默认值),则预期请求将按照使用expectRequest设置的相同顺序找到。

browser.getRequest(index: number, { includePending?: boolean, orderBy?: 'START' | 'END' }?: = {})

要对特定请求进行更复杂的断言,您可以获取特定请求的详细信息。您必须提供要访问的请求的基于 0 的索引,按照请求完成的顺序(默认值)或发起的时间(通过传递orderBy: 'START'选项)。

  • indexnumber):要访问的请求的编号
  • optionsobject):配置选项
  • options.includePending (布尔值): 是否返回尚未完成的请求。默认情况下,此值为 false,以匹配 v4.1.10 及更早版本库的行为。
  • options.orderBy ('START' | 'END'): 请求应如何排序。默认情况下,此值为 'END',以匹配 v4.1.10 及更早版本库的行为。如果为 'START',则请求将按发起时间排序,而不是按请求完成时间排序。(由于挂起的请求尚未完成,因此当按 'END' 排序时,所有挂起的请求都将在所有已完成的请求之后。)

返回 request 对象

  • request.url: 请求的 URL
  • request.method: 使用的 HTTP 方法
  • request.body: 请求中使用的有效负载/主体数据
  • request.headers: 请求 HTTP 头部,作为 JS 对象
  • request.pending: 布尔标志,指示此请求是否已完成(即是否具有 response 属性)或正在进行中。
  • request.response: 仅当请求完成时(即 request.pending === false)才存在的 JS 对象,包含有关响应的数据。
  • request.response?.headers: 响应 HTTP 头部,作为 JS 对象
  • request.response?.body: 响应主体(如果可能,将解析为 JSON)
  • request.response?.statusCode: 响应状态码

关于 request.body 的说明:wdio-intercept-service 将尝试按如下方式解析请求主体

  • 字符串:直接返回字符串 ('value')
  • JSON:使用 JSON.parse() 解析 JSON 对象 (({ key: value }))
  • FormData:将以 { key: [value1, value2, ...] } 的格式输出 FormData
  • ArrayBuffer:将尝试将缓冲区转换为字符串(实验性)
  • 其他任何内容:将对您的数据使用强制的 JSON.stringify()。祝你好运!

对于 fetch API,我们仅支持字符串和 JSON 数据!

browser.getRequests({ includePending?: boolean, orderBy?: 'START' | 'END' }?: = {})

获取所有捕获的请求作为数组,支持与 getRequest 相同的可选选项。

返回 request 对象数组。

browser.hasPendingRequests()

一个实用程序方法,用于检查是否有任何 HTTP 请求仍在挂起。测试可以使用它来确保所有请求在合理的时间内完成,或验证对 getRequests()assertRequests() 的调用是否包含所有所需的 HTTP 请求。

返回 布尔值

TypeScript 支持

此插件提供自己的 TS 类型。只需将您的 tsconfig 指向类型扩展,如此处所述。

"compilerOptions": {
// ..
"types": ["node", "webdriverio", "wdio-intercept-service"]
},

运行测试

需要最新版本的 Chrome 和 Firefox 才能在本地运行测试。您可能需要更新 chromedrivergeckodriver 依赖项以匹配系统上安装的版本。

npm test

贡献

我欢迎任何贡献。只需打开一个问题或直接提交 PR。
请注意,此拦截器库是为与 Internet Explorer 等旧版浏览器配合使用而编写的。因此,lib/interceptor.js 中使用的任何代码都必须至少可由 Internet Explorer 的 JavaScript 运行时解析。

许可证

MIT

欢迎!我如何帮助您?

WebdriverIO AI Copilot