Anfrage-Mocks und Spies
WebdriverIO bietet integrierte Unterstützung für die Modifikation von Netzwerkantworten, damit Sie sich auf das Testen Ihrer Frontend-Anwendung konzentrieren können, ohne ein Backend oder einen Mock-Server einrichten zu müssen. Sie können benutzerdefinierte Antworten für Web-Ressourcen wie REST-API-Anfragen in Ihrem Test definieren und diese dynamisch ändern.
Beachten Sie, dass die Verwendung des mock
-Befehls Unterstützung für das Chrome DevTools-Protokoll erfordert. Diese Unterstützung ist gegeben, wenn Sie Tests lokal in einem Chromium-basierten Browser ausführen, über ein Selenium Grid v4 oder höher oder über einen Cloud-Anbieter mit Unterstützung für das Chrome DevTools-Protokoll (z.B. SauceLabs, BrowserStack, LambdaTest). Vollständige browserübergreifende Unterstützung wird verfügbar sein, sobald die erforderlichen Grundlagen in Webdriver Bidi implementiert und in den jeweiligen Browsern umgesetzt werden.
Erstellen eines Mocks
Bevor Sie Antworten modifizieren können, müssen Sie zuerst einen Mock definieren. Dieser Mock wird durch die Ressourcen-URL beschrieben und kann nach der Anfragemethode oder Headers gefiltert werden. Die Ressource unterstützt Glob-Ausdrücke durch minimatch:
// mock all resources ending with "/users/list"
const userListMock = await browser.mock('**/users/list')
// or you can specify the mock by filtering resources by headers or
// status code, only mock successful requests to json resources
const strictMock = await browser.mock('**', {
// mock all json responses
requestHeaders: { 'Content-Type': 'application/json' },
// that were successful
statusCode: 200
})
Festlegen benutzerdefinierter Antworten
Sobald Sie einen Mock definiert haben, können Sie benutzerdefinierte Antworten dafür festlegen. Diese benutzerdefinierten Antworten können entweder ein Objekt sein, um eine JSON-Antwort zu geben, eine lokale Datei, um mit einem benutzerdefinierten Fixture zu antworten, oder eine Web-Ressource, um die Antwort mit einer Ressource aus dem Internet zu ersetzen.
Mocken von API-Anfragen
Um API-Anfragen zu mocken, bei denen Sie eine JSON-Antwort erwarten, müssen Sie lediglich respond
auf dem Mock-Objekt mit einem beliebigen Objekt aufrufen, das Sie zurückgeben möchten, z.B.:
const mock = await browser.mock('https://todo-backend-express-knex.herokuapp.com/')
mock.respond([{
title: 'Injected (non) completed Todo',
order: null,
completed: false
}, {
title: 'Injected completed Todo',
order: null,
completed: true
}], {
headers: {
'Access-Control-Allow-Origin': '*'
},
fetchResponse: false
})
await browser.url('https://todobackend.com/client/index.html?https://todo-backend-express-knex.herokuapp.com/')
await $('#todo-list li').waitForExist()
console.log(await $$('#todo-list li').map(el => el.getText()))
// outputs: "[ 'Injected (non) completed Todo', 'Injected completed Todo' ]"
Sie können auch die Antwort-Header sowie den Statuscode ändern, indem Sie einige Mock-Antwortparameter wie folgt übergeben:
mock.respond({ ... }, {
// respond with status code 404
statusCode: 404,
// merge response headers with following headers
headers: { 'x-custom-header': 'foobar' }
})
Wenn Sie möchten, dass der Mock das Backend überhaupt nicht aufruft, können Sie false
für das Flag fetchResponse
übergeben.
mock.respond({ ... }, {
// do not call the actual backend
fetchResponse: false
})
Es wird empfohlen, benutzerdefinierte Antworten in Fixture-Dateien zu speichern, damit Sie sie in Ihrem Test einfach importieren können:
// requires Node.js v16.14.0 or higher to support JSON import assertions
import responseFixture from './__fixtures__/apiResponse.json' assert { type: 'json' }
mock.respond(responseFixture)
Mocken von Textressourcen
Wenn Sie Textressourcen wie JavaScript, CSS-Dateien oder andere textbasierte Ressourcen modifizieren möchten, können Sie einfach einen Dateipfad übergeben, und WebdriverIO ersetzt die ursprüngliche Ressource damit, z.B.:
const scriptMock = await browser.mock('**/script.min.js')
scriptMock.respond('./tests/fixtures/script.js')
// or respond with your custom JS
scriptMock.respond('alert("I am a mocked resource")')
Umleiten von Web-Ressourcen
Sie können auch einfach eine Web-Ressource durch eine andere Web-Ressource ersetzen, wenn Ihre gewünschte Antwort bereits im Web gehostet wird. Dies funktioniert sowohl mit einzelnen Seitenressourcen als auch mit einer Webseite selbst, z.B.:
const pageMock = await browser.mock('https://google.com/')
await pageMock.respond('https://webdriver.io')
await browser.url('https://google.com')
console.log(await browser.getTitle()) // returns "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js"
Dynamische Antworten
Wenn Ihre Mock-Antwort von der ursprünglichen Ressourcenantwort abhängt, können Sie die Ressource auch dynamisch modifizieren, indem Sie eine Funktion übergeben, die die ursprüngliche Antwort als Parameter erhält und den Mock basierend auf dem Rückgabewert setzt, z.B.:
const mock = await browser.mock('https://todo-backend-express-knex.herokuapp.com/', {
method: 'get'
})
mock.respond((req) => {
// replace todo content with their list number
return req.body.map((item, i) => ({ ...item, title: i }))
})
await browser.url('https://todobackend.com/client/index.html?https://todo-backend-express-knex.herokuapp.com/')
await $('#todo-list li').waitForExist()
console.log(await $$('#todo-list li label').map((el) => el.getText()))
// returns
// [
// '0', '1', '2', '19', '20',
// '21', '3', '4', '5', '6',
// '7', '8', '9', '10', '11',
// '12', '13', '14', '15', '16',
// '17', '18', '22'
// ]
Abbrechen von Mocks
Anstatt eine benutzerdefinierte Antwort zurückzugeben, können Sie die Anfrage auch einfach mit einem der folgenden HTTP-Fehler abbrechen:
- Failed
- Aborted
- TimedOut
- AccessDenied
- ConnectionClosed
- ConnectionReset
- ConnectionRefused
- ConnectionAborted
- ConnectionFailed
- NameNotResolved
- InternetDisconnected
- AddressUnreachable
- BlockedByClient
- BlockedByResponse
Dies ist sehr nützlich, wenn Sie Skripte von Drittanbietern von Ihrer Seite blockieren möchten, die einen negativen Einfluss auf Ihren Funktionstest haben. Sie können einen Mock abbrechen, indem Sie einfach abort
oder abortOnce
aufrufen, z.B.:
const mock = await browser.mock('https://www.google-analytics.com/**')
mock.abort('Failed')
Spies
Jeder Mock ist automatisch ein Spy, der die Anzahl der Anfragen zählt, die der Browser an diese Ressource gestellt hat. Wenn Sie keine benutzerdefinierte Antwort oder keinen Abbruchgrund auf den Mock anwenden, wird mit der Standardantwort fortgefahren, die Sie normalerweise erhalten würden. Dies ermöglicht es Ihnen zu überprüfen, wie oft der Browser die Anfrage gestellt hat, z.B. an einen bestimmten API-Endpunkt.
const mock = await browser.mock('**/user', { method: 'post' })
console.log(mock.calls.length) // returns 0
// register user
await $('#username').setValue('randomUser')
await $('password').setValue('password123')
await $('password_repeat').setValue('password123')
await $('button[type="submit"]').click()
// check if API request was made
expect(mock.calls.length).toBe(1)
// assert response
expect(mock.calls[0].body).toEqual({ success: true })