Skip to content

Commit

Permalink
feat: mock route for ppt (#4262)
Browse files Browse the repository at this point in the history
  • Loading branch information
kobenguyent authored Mar 18, 2024
1 parent 6175f8f commit 74a73e0
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 73 deletions.
4 changes: 2 additions & 2 deletions docs/helpers/Playwright.md
Original file line number Diff line number Diff line change
Expand Up @@ -1505,7 +1505,7 @@ This method allows intercepting and mocking requests & responses. [Learn more ab
#### Parameters

- `url` **([string][9] | [RegExp][11])?** URL, regex or pattern for to match URL
- `handler` **[function][21]?** a function to process reques
- `handler` **[function][21]?** a function to process request

### mockTraffic

Expand Down Expand Up @@ -2230,7 +2230,7 @@ If no handler is passed, all mock requests for the rote are disabled.
#### Parameters

- `url` **([string][9] | [RegExp][11])?** URL, regex or pattern for to match URL
- `handler` **[function][21]?** a function to process reques
- `handler` **[function][21]?** a function to process request

### stopRecordingTraffic

Expand Down
91 changes: 61 additions & 30 deletions docs/helpers/Puppeteer.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,26 @@ Type: [object][4]

- `url` **[string][6]** base url of website to be tested
- `basicAuth` **[object][4]?** (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
- `show` **[boolean][20]?** show Google Chrome window for debug.
- `restart` **[boolean][20]?** restart browser between tests.
- `disableScreenshots` **[boolean][20]?** don't save screenshot on failure.
- `fullPageScreenshots` **[boolean][20]?** make full page screenshots on failure.
- `uniqueScreenshotNames` **[boolean][20]?** option to prevent screenshot override if you have scenarios with the same name in different suites.
- `trace` **[boolean][20]?** record [tracing information][24] with screenshots.
- `keepTraceForPassedTests` **[boolean][20]?** save trace for passed tests.
- `keepBrowserState` **[boolean][20]?** keep browser state between tests when `restart` is set to false.
- `keepCookies` **[boolean][20]?** keep cookies between tests when `restart` is set to false.
- `show` **[boolean][22]?** show Google Chrome window for debug.
- `restart` **[boolean][22]?** restart browser between tests.
- `disableScreenshots` **[boolean][22]?** don't save screenshot on failure.
- `fullPageScreenshots` **[boolean][22]?** make full page screenshots on failure.
- `uniqueScreenshotNames` **[boolean][22]?** option to prevent screenshot override if you have scenarios with the same name in different suites.
- `trace` **[boolean][22]?** record [tracing information][26] with screenshots.
- `keepTraceForPassedTests` **[boolean][22]?** save trace for passed tests.
- `keepBrowserState` **[boolean][22]?** keep browser state between tests when `restart` is set to false.
- `keepCookies` **[boolean][22]?** keep cookies between tests when `restart` is set to false.
- `waitForAction` **[number][10]?** how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
- `waitForNavigation` **[string][6]?** when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API][23]. Array values are accepted as well.
- `waitForNavigation` **[string][6]?** when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API][25]. Array values are accepted as well.
- `pressKeyDelay` **[number][10]?** delay between key presses in ms. Used when calling Puppeteers page.type(...) in fillField/appendField
- `getPageTimeout` **[number][10]?** config option to set maximum navigation time in milliseconds. If the timeout is set to 0, then timeout will be disabled.
- `waitForTimeout` **[number][10]?** default wait* timeout in ms.
- `windowSize` **[string][6]?** default window size. Set a dimension in format WIDTHxHEIGHT like `640x480`.
- `userAgent` **[string][6]?** user-agent string.
- `manualStart` **[boolean][20]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
- `manualStart` **[boolean][22]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
- `browser` **[string][6]?** can be changed to `firefox` when using [puppeteer-firefox][2].
- `chrome` **[object][4]?** pass additional [Puppeteer run options][25].
- `highlightElement` **[boolean][20]?** highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
- `chrome` **[object][4]?** pass additional [Puppeteer run options][27].
- `highlightElement` **[boolean][22]?** highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).



Expand Down Expand Up @@ -1255,6 +1255,21 @@ I.seeFile('avatar.jpg');
- `downloadPath` **[string][6]** change this parameter to set another directory for saving
### mockRoute
Mocks network request using [`Request Interception`][17]
```js
I.mockRoute(/(.png$)|(.jpg$)/, route => route.abort());
```
This method allows intercepting and mocking requests & responses. [Learn more about it][17]
#### Parameters
- `url` **([string][6] | [RegExp][18])?** URL, regex or pattern for to match URL
- `handler` **[function][12]?** a function to process request
### moveCursorTo
Moves cursor to element matched by locator.
Expand Down Expand Up @@ -1287,11 +1302,11 @@ I.openNewTab();
### pressKey
_Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([GoogleChrome/puppeteer#1313][17]).
_Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([GoogleChrome/puppeteer#1313][19]).
Presses a key in the browser (on a focused element).
_Hint:_ For populating text field or textarea, it is recommended to use [`fillField`][18].
_Hint:_ For populating text field or textarea, it is recommended to use [`fillField`][20].
```js
I.pressKey('Backspace');
Expand Down Expand Up @@ -1358,7 +1373,7 @@ Returns **void** automatically synchronized promise through #recorder
Presses a key in the browser and leaves it in a down state.
To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][19]).
To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][21]).
```js
I.pressKeyDown('Control');
Expand All @@ -1376,7 +1391,7 @@ Returns **void** automatically synchronized promise through #recorder
Releases a key in the browser which was previously set to a down state.
To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][19]).
To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][21]).
```js
I.pressKeyDown('Control');
Expand Down Expand Up @@ -1470,7 +1485,7 @@ I.saveScreenshot('debug.png', true) //resizes to available scrollHeight and scro
#### Parameters
- `fileName` **[string][6]** file name to save.
- `fullPage` **[boolean][20]** (optional, `false` by default) flag to enable fullscreen screenshot mode.
- `fullPage` **[boolean][22]** (optional, `false` by default) flag to enable fullscreen screenshot mode.
Returns **void** automatically synchronized promise through #recorder
Expand Down Expand Up @@ -1862,6 +1877,18 @@ I.setPuppeteerRequestHeaders({
- `customHeaders` **[object][4]** headers to set
### stopMockingRoute
Stops network mocking created by `mockRoute`.
```js
I.stopMockingRoute(/(.png$)|(.jpg$)/);
```
#### Parameters
- `url` **([string][6] | [RegExp][18])?** URL, regex or pattern for to match URL
### switchTo
Switches frame or in case of null locator reverts to parent.
Expand Down Expand Up @@ -1907,7 +1934,7 @@ I.switchToPreviousTab(2);
Types out the given text into an active field.
To slow down typing use a second parameter, to set interval between key presses.
_Note:_ Should be used when [`fillField`][18] is not an option.
_Note:_ Should be used when [`fillField`][20] is not an option.
```js
// passing in a string
Expand Down Expand Up @@ -1958,7 +1985,7 @@ Use Puppeteer API inside a test.
First argument is a description of an action.
Second argument is async function that gets this helper as parameter.
{ [`page`][21], [`browser`][22] } from Puppeteer API are available.
{ [`page`][23], [`browser`][24] } from Puppeteer API are available.
```js
I.usePuppeteerTo('emulate offline mode', async ({ page }) {
Expand Down Expand Up @@ -2110,7 +2137,7 @@ Returns **void** automatically synchronized promise through #recorder
Waits for navigation to finish. By default, takes configured `waitForNavigation` option.
See [Puppeteer's reference][23]
See [Puppeteer's reference][25]
#### Parameters
Expand Down Expand Up @@ -2313,20 +2340,24 @@ Returns **void** automatically synchronized promise through #recorder
[16]: https://codecept.io/helpers/FileSystem
[17]: https://github.com/GoogleChrome/puppeteer/issues/1313
[17]: https://pptr.dev/next/guides/request-interception
[18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp
[19]: https://github.com/GoogleChrome/puppeteer/issues/1313
[18]: #fillfield
[20]: #fillfield
[19]: #click
[21]: #click
[20]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[22]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[21]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page
[23]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page
[22]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser
[24]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser
[23]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions
[25]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions
[24]: https://pptr.dev/api/puppeteer.tracing
[26]: https://pptr.dev/api/puppeteer.tracing
[25]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions
[27]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions
54 changes: 15 additions & 39 deletions docs/puppeteer.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,52 +216,28 @@ await eachElement(

> ℹ Learn more about [eachElement plugin](/plugins/#eachelement)
## Mocking Requests
## Mocking Network Requests <Badge text="Since 3.5.16" type="warning"/>

Web application sends various requests to local services (Rest API, GraphQL) or to 3rd party services (CDNS, Google Analytics, etc).
When you run tests with Puppeteer you can control those requests by mocking them. For instance, you can speed up your tests by blocking trackers, Google Analytics, and other services you don't control.

Also you can replace real request with a one explicitly defined. This is useful when you want to isolate application testing from a backend. For instance, if you don't want to save data to database, and you know the request which performs save, you can mock the request, so application will treat this as valid response, but no data will be actually saved.

To mock requests enable additional helper [MockRequest](/helpers/MockRequest) (which is based on Polly.js).
Network requests & responses can be mocked and modified. Use `mockRoute` which strictly follows [Puppeteer's `setRequestInterception` API](https://pptr.dev/next/api/puppeteer.page.setrequestinterception).

```js
helpers: {
Puppeteer: {
// regular Puppeteer config here
},
MockRequest: {}
}
```

And install additional packages:

```
npm i @pollyjs/core @pollyjs/adapter-puppeteer --save-dev
```

After an installation function `mockRequest` will be added to `I` object. You can use it to explicitly define which requests to block and which response they should return instead:

```js
// block all Google Analytics calls
I.mockRequest('/google-analytics/*path', 200);
// return an empty successful response
I.mockRequest('GET', '/api/users', 200);
// block post requests to /api/users and return predefined object
I.mockRequest('POST', '/api/users', { user: 'davert' });
// return error request with body
I.mockRequest('GET', '/api/users/1', 404, { error: 'User not found' });
```

> See [`mockRequest` API](/helpers/MockRequest#mockrequest)
I.mockRoute('https://reqres.in/api/comments/1', request => {
request.respond({
status: 200,
headers: { 'Access-Control-Allow-Origin': '*' },
contentType: 'application/json',
body: '{"name": "this was mocked" }',
});
})

To see `mockRequest` method in intellisense auto completion don't forget to run `codeceptjs def` command:
I.mockRoute('**/*.{png,jpg,jpeg}', route => route.abort());

```
npx codeceptjs def
// To disable mocking for a route call `stopMockingRoute`
// for previously mocked URL
I.stopMockingRoute('**/*.{png,jpg,jpeg}'
```
Mocking rules will be kept while a test is running. To stop mocking use `I.stopMocking()` command
To master request intercepting [use `HTTPRequest` object](https://pptr.dev/next/api/puppeteer.httprequest) object passed into mock request handler.
## Accessing Puppeteer API
Expand Down
4 changes: 2 additions & 2 deletions lib/helper/Playwright.js
Original file line number Diff line number Diff line change
Expand Up @@ -2957,7 +2957,7 @@ class Playwright extends Helper {
* This method allows intercepting and mocking requests & responses. [Learn more about it](https://playwright.dev/docs/network#handle-requests)
*
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
* @param {function} [handler] a function to process reques
* @param {function} [handler] a function to process request
*/
async mockRoute(url, handler) {
return this.browserContext.route(...arguments);
Expand All @@ -2973,7 +2973,7 @@ class Playwright extends Helper {
* If no handler is passed, all mock requests for the rote are disabled.
*
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
* @param {function} [handler] a function to process reques
* @param {function} [handler] a function to process request
*/
async stopMockingRoute(url, handler) {
return this.browserContext.unroute(...arguments);
Expand Down
48 changes: 48 additions & 0 deletions lib/helper/Puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2459,6 +2459,54 @@ class Puppeteer extends Helper {
if (prop) return rect[prop];
return rect;
}

/**
* Mocks network request using [`Request Interception`](https://pptr.dev/next/guides/request-interception)
*
* ```js
* I.mockRoute(/(\.png$)|(\.jpg$)/, route => route.abort());
* ```
* This method allows intercepting and mocking requests & responses. [Learn more about it](https://pptr.dev/next/guides/request-interception)
*
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
* @param {function} [handler] a function to process request
*/
async mockRoute(url, handler) {
await this.page.setRequestInterception(true);

this.page.on('request', interceptedRequest => {
if (interceptedRequest.url().match(url)) {
// @ts-ignore
handler(interceptedRequest);
} else {
interceptedRequest.continue();
}
});
}

/**
* Stops network mocking created by `mockRoute`.
*
* ```js
* I.stopMockingRoute(/(\.png$)|(\.jpg$)/);
* ```
*
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
*/
async stopMockingRoute(url) {
await this.page.setRequestInterception(true);

this.page.off('request');

// Resume normal request handling for the given URL
this.page.on('request', interceptedRequest => {
if (interceptedRequest.url().includes(url)) {
interceptedRequest.continue();
} else {
interceptedRequest.continue();
}
});
}
}

module.exports = Puppeteer;
Expand Down
20 changes: 20 additions & 0 deletions test/helper/Puppeteer_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,26 @@ describe('Puppeteer', function () {
assert.equal('TestEd Beta 2.0', title);
});
});

describe('#mockRoute, #stopMockingRoute', () => {
it('should mock a route', async () => {
await I.amOnPage('/form/fetch_call');
await I.mockRoute('https://reqres.in/api/comments/1', request => {
request.respond({
status: 200,
headers: { 'Access-Control-Allow-Origin': '*' },
contentType: 'application/json',
body: '{"name": "this was mocked" }',
});
});
await I.click('GET COMMENTS');
await I.see('this was mocked');
await I.stopMockingRoute('https://reqres.in/api/comments/1');
await I.click('GET COMMENTS');
await I.see('data');
await I.dontSee('this was mocked');
});
});
});

let remoteBrowser;
Expand Down

0 comments on commit 74a73e0

Please sign in to comment.