From 2fd0982372fe2065855d897c983ccf0ce85fa1cc Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 30 Nov 2022 19:29:14 -0800 Subject: [PATCH] docs: improve API mocking docs (#19189) --- docs/src/api/class-route.md | 9 +- docs/src/{mock-js.md => mock-browser-js.md} | 4 +- docs/src/mock.md | 123 ++++++++++++++++++++ 3 files changed, 130 insertions(+), 6 deletions(-) rename docs/src/{mock-js.md => mock-browser-js.md} (99%) create mode 100644 docs/src/mock.md diff --git a/docs/src/api/class-route.md b/docs/src/api/class-route.md index 37293c0a2f..6e1c82e75d 100644 --- a/docs/src/api/class-route.md +++ b/docs/src/api/class-route.md @@ -430,7 +430,8 @@ await page.route('https://dog.ceo/api/breeds/list/all', async route => { page.route("https://dog.ceo/api/breeds/list/all", route -> { APIResponse response = route.fetch(); JsonObject json = new Gson().fromJson(response.text(), JsonObject.class); - json.set("big_red_dog", new JsonArray()); + JsonObject message = itemObj.get("json").getAsJsonObject(); + message.set("big_red_dog", new JsonArray()); route.fulfill(new Route.FulfillOptions() .setResponse(response) .setBody(json.toString())); @@ -441,7 +442,7 @@ page.route("https://dog.ceo/api/breeds/list/all", route -> { async def handle(route): response = await route.fulfill() json = await response.json() - json["big_red_dog"] = [] + json["message"]["big_red_dog"] = [] await route.fulfill(response=response, json=json) await page.route("https://dog.ceo/api/breeds/list/all", handle) @@ -451,7 +452,7 @@ await page.route("https://dog.ceo/api/breeds/list/all", handle) def handle(route): response = route.fulfill() json = response.json() - json["big_red_dog"] = [] + json["message"]["big_red_dog"] = [] route.fulfill(response=response, json=json) page.route("https://dog.ceo/api/breeds/list/all", handle) @@ -462,7 +463,7 @@ await page.RouteAsync("https://dog.ceo/api/breeds/list/all", async route => { var response = await route.FetchAsync(); dynamic json = await response.JsonAsync(); - json.big_red_dog = new string[] {}; + json.message.big_red_dog = new string[] {}; await route.FulfillAsync(new() { Response = response, Json = json }); }); ``` diff --git a/docs/src/mock-js.md b/docs/src/mock-browser-js.md similarity index 99% rename from docs/src/mock-js.md rename to docs/src/mock-browser-js.md index c50e25f86c..b249088d0a 100644 --- a/docs/src/mock-js.md +++ b/docs/src/mock-browser-js.md @@ -1,6 +1,6 @@ --- -id: mock -title: "Mock APIs" +id: mock-browser-apis +title: "Mock Browser APIs" --- Playwright provides native support for most of the browser features. However, there are some experimental APIs diff --git a/docs/src/mock.md b/docs/src/mock.md new file mode 100644 index 0000000000..f0d17bddb0 --- /dev/null +++ b/docs/src/mock.md @@ -0,0 +1,123 @@ +--- +id: mocj +title: "Mock APIs" +--- + +Web APIs are usually implemented as HTTP endpoints. Playwright provides APIs to **mock** and **modify** network traffic, both HTTP and HTTPS. Any requests that a page does, including [XHRs](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) and +[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) requests, can be tracked, modified and mocked. + +## Mock API requests + +Following code will intercept all the calls to `https://dog.ceo/api/breeds/list/all` and will return +the test data instead. No requests to the `https://dog.ceo/api/breeds/list/all` endpoint will be made. + +Read more about [advanced networking](./network.md). + +```js +await page.route('https://dog.ceo/api/breeds/list/all', async route => { + const json = { + message: { 'test_breed': [] } + }; + await route.fulfill({ json }); +}); +``` + +```python async +async def handle(route): + json = { message: { "test_breed": [] } } + await route.fulfill(json=json) + +await page.route("https://dog.ceo/api/breeds/list/all", handle) +``` + +```python sync +async def handle(route): + json = { message: { "test_breed": [] } } + route.fulfill(json=json) + +page.route("https://dog.ceo/api/breeds/list/all", handle) +``` + +```csharp +await page.RouteAsync("https://dog.ceo/api/breeds/list/all", async route => +{ + var json = /* JsonElement with the test payload */; + await route.FulfillAsync(new () { Json: json }); +}); +``` + +```java +page.route("https://dog.ceo/api/breeds/list/all", route -> { + route.fulfill(new Route.FulfillOptions() + .setBody("{\"message\":{\"test_breed\":[]}}")); +}); +``` + +## Modify API responses + +Sometimes, it is essential to make an API request, but response needs to be patched to +allow for reproducible testing. In that case, instead of mocking the request, one +can perform the request and fulfill it with the modified response. + +Read more about [advanced networking](./network.md). + +```js +await page.route('https://dog.ceo/api/breeds/list/all', async route => { + const response = await route.fetch(); + const json = await response.json(); + json.message['big_red_dog'] = []; + // Fullfill using the original response, while patching the response body + // with the given JSON object. + await route.fulfill({ response, json }); +}); +``` + +```python async +async def handle(route): + response = await route.fulfill() + json = await response.json() + json["message"]["big_red_dog"] = [] + # Fullfill using the original response, while patching the response body + # with the given JSON object. + await route.fulfill(response=response, json=json) + +await page.route("https://dog.ceo/api/breeds/list/all", handle) +``` + +```python sync +def handle(route): + response = route.fulfill() + json = response.json() + json["message"]["big_red_dog"] = [] + # Fullfill using the original response, while patching the response body + # with the given JSON object. + route.fulfill(response=response, json=json) + +page.route("https://dog.ceo/api/breeds/list/all", handle) +``` + +```csharp +await page.RouteAsync("https://dog.ceo/api/breeds/list/all", async route => +{ + var response = await route.FetchAsync(); + dynamic json = await response.JsonAsync(); + json.message.big_red_dog = new string[] {}; + // Fullfill using the original response, while patching the response body + // with the given JSON object. + await route.FulfillAsync(new() { Response = response, Json = json }); +}); +``` + +```java +page.route("https://dog.ceo/api/breeds/list/all", route -> { + APIResponse response = route.fetch(); + JsonObject json = new Gson().fromJson(response.text(), JsonObject.class); + JsonObject message = json.get("message").getAsJsonObject(); + message.set("big_red_dog", new JsonArray()); + // Fullfill using the original response, while patching the response body + // with the given JSON object. + route.fulfill(new Route.FulfillOptions() + .setResponse(response) + .setBody(json.toString())); +}); +```