拦截服务
🕸 在webdriver.io中捕获和断言 HTTP ajax 调用
这是一个用于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 独立版时,需要手动调用 before
和 beforeTest
/ 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'
,则请求将根据其开始时间排序。includePending
(boolean
):此选项控制是否返回尚未完成的请求。为了与现有版本的此库保持向后兼容,默认值为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 请求进行预期。可以(并且应该)进行链接。预期的顺序应与正在发出的请求的顺序相对应。
method
(String
):预期的 http 方法。可以是xhr.open()
作为第一个参数接受的任何内容。url
(String
|RegExp
):请求中调用的确切 URL,作为字符串或 RegExp 进行匹配statusCode
(Number
):响应的预期状态码
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'
选项)。
index
(number
):要访问的请求的编号options
(object
):配置选项options.includePending
(布尔值
): 是否返回尚未完成的请求。默认情况下,此值为 false,以匹配 v4.1.10 及更早版本库的行为。options.orderBy
('START' | 'END'
): 请求应如何排序。默认情况下,此值为'END'
,以匹配 v4.1.10 及更早版本库的行为。如果为'START'
,则请求将按发起时间排序,而不是按请求完成时间排序。(由于挂起的请求尚未完成,因此当按'END'
排序时,所有挂起的请求都将在所有已完成的请求之后。)
返回 request
对象
request.url
: 请求的 URLrequest.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 才能在本地运行测试。您可能需要更新 chromedriver
和 geckodriver
依赖项以匹配系统上安装的版本。
npm test
贡献
我欢迎任何贡献。只需打开一个问题或直接提交 PR。
请注意,此拦截器库是为与 Internet Explorer 等旧版浏览器配合使用而编写的。因此,lib/interceptor.js
中使用的任何代码都必须至少可由 Internet Explorer 的 JavaScript 运行时解析。
许可证
MIT