模拟对象
模拟对象是表示网络模拟的对象,包含有关匹配给定url
和filterOptions
的请求的信息。可以使用mock
命令获取它。
信息
请注意,使用mock
命令需要支持Chrome DevTools协议。
如果您在基于Chromium的浏览器中本地运行测试,或者
使用Selenium Grid v4或更高版本,则可以获得该支持。此命令不能在云中运行
自动化测试时使用。在自动化协议部分了解更多信息。
您可以在我们的模拟和监视指南中阅读更多关于在WebdriverIO中模拟请求和响应的信息。
属性
模拟对象包含以下属性:
名称 | 类型 | 详情 |
---|---|---|
url | String | 传递给mock命令的url |
filterOptions | Object | 传递给mock命令的资源过滤选项 |
browser | Object | 用于获取模拟对象的浏览器对象。 |
calls | Object[] | 关于匹配的浏览器请求的信息,包含诸如url 、method 、headers 、initialPriority 、referrerPolic 、statusCode 、responseHeaders 和body 等属性 |
方法
模拟对象提供了各种命令,列在mock
部分,允许用户修改请求或响应的行为。
事件
模拟对象是一个EventEmitter,并且会发出几个事件供您使用。
以下是事件列表。
request
当发起匹配模拟模式的网络请求时,会发出此事件。请求会在事件回调中传入。
请求接口:
interface RequestEvent {
requestId: number
request: Matches
responseStatusCode: number
responseHeaders: Record<string, string>
}
overwrite
当网络响应被respond
或respondOnce
覆盖时,会发出此事件。响应会在事件回调中传入。
响应接口:
interface OverwriteEvent {
requestId: number
responseCode: number
responseHeaders: Record<string, string>
body?: string | Record<string, any>
}
fail
当网络请求被abort
或abortOnce
中止时,会发出此事件。失败信息会在事件回调中传入。
失败接口:
interface FailEvent {
requestId: number
errorReason: Protocol.Network.ErrorReason
}
match
当添加新匹配时,在continue
或overwrite
之前会发出此事件。匹配信息会在事件回调中传入。
匹配接口:
interface MatchEvent {
url: string // 请求URL(不含片段)。
urlFragment?: string // 请求URL的片段,从哈希开始(如果存在)。
method: string // HTTP请求方法。
headers: Record<string, string> // HTTP请求头。
postData?: string // HTTP POST请求数据。
hasPostData?: boolean // 当请求有POST数据时为true。
mixedContentType?: MixedContentType // 请求的混合内容导出类型。
initialPriority: ResourcePriority // 发送请求时资源请求的优先级。
referrerPolicy: ReferrerPolicy // 请求的引用策略,如https://www.w3.org/TR/referrer-policy/中定义的。
isLinkPreload?: boolean // 是否通过链接预加载。
body: string | Buffer | JsonCompatible // 实际资源的响应体。
responseHeaders: Record<string, string> // HTTP响应头。
statusCode: number // HTTP响应状态码。
mockedResponse?: string | Buffer // 如果mock发出事件,也修改了它的响应。
}
continue
当网络响应既未被覆盖也未被中断,或者响应已被另一个模拟发送时,会发出此事件。requestId
会在事件回调中传入。
示例
获取待处理请求的数量:
let pendingRequests = 0
const mock = await browser.mock('**') // 匹配所有请求很重要,否则,结果值可能会很混乱。
mock.on('request', ({request}) => {
pendingRequests++
console.log(`matched request to ${request.url}, pending ${pendingRequests} requests`)
})
mock.on('match', ({url}) => {
pendingRequests--
console.log(`resolved request to ${url}, pending ${pendingRequests} requests`)
})
在404网络失败时抛出错误:
browser.addCommand('loadPageWithout404', (url, {selector, predicate}) => new Promise(async (resolve, reject) => {
const mock = await this.mock('**')
mock.on('match', ({url, statusCode}) => {
if (statusCode === 404) {
reject(new Error(`request to ${url} failed with "Not Found"`))
}
})
await this.url(url).catch(reject)
// 在这里等待,因为一些请求可能仍在等待中
if (selector) {
await this.$(selector).waitForExist().catch(reject)
}
if (predicate) {
await this.waitUntil(predicate).catch(reject)
}
resolve()
}))
await browser.loadPageWithout404(browser, 'some/url', { selector: 'main' })
确定是否使用了模拟响应值:
const firstMock = await browser.mock('**/foo/**')
const secondMock = await browser.mock('**/foo/bar/**')
firstMock.respondOnce({id: 3, title: 'three'})
secondMock.respond({id: 4, title: 'four'})
firstMock.on('overwrite', () => {
// 对第一个 '**/foo/**' 请求触发
}).on('continue', () => {
// 对其余 '**/foo/**' 请求触发
})
secondMock.on('continue', () => {
// 对第一个 '**/foo/bar/**' 请求触发
}).on('overwrite', () => {
// 对其余 '**/foo/bar/**' 请求触发
})
在这个例子中,firstMock
先定义并有一个respondOnce
调用,所以对于第一个请求不会使用secondMock
的响应值,但会用于其余请求。