Skip to content

Commit c7e851a

Browse files
Mocking (#17)
* fixed issue that opens page from browser, not from context * added mocking steps
1 parent 022cd3d commit c7e851a

File tree

7 files changed

+170
-2
lines changed

7 files changed

+170
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## Current
1+
## 0.0.8
22
- :beetle: fixed issue that opens page from browser, not from context
3+
- :rocket: added mock steps
34

45
## 0.0.7
56
- :rocket: added capability to connect via CDP

src/mock.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { When } from '@cucumber/cucumber';
2+
import { getValue } from './transformers';
3+
import memory from '@qavajs/memory';
4+
import { Route } from '@playwright/test';
5+
6+
/**
7+
* Create simple mock instance
8+
* @param {string} urlTemplate - minimatch url template to mock
9+
* @param {string} memoryKey - memory key to store mock instance
10+
* @example When I create mock for '/yourservice/**' as 'mock1'
11+
* @example When I create mock for '$mockUrlTemplate' as 'mock1'
12+
*/
13+
When('I create mock for {string} as {string}', async function (urlTemplate: string, memoryKey: string) {
14+
const url = await getValue(urlTemplate);
15+
memory.setValue(memoryKey, url);
16+
});
17+
18+
async function respondWith(mockKey: string, statusCode: string, body: string): Promise<void> {
19+
const mockUrl: string = await getValue(mockKey);
20+
const responseStatusCode: number = parseInt(await getValue(statusCode));
21+
const responseBody = await getValue(body);
22+
await page.route(mockUrl, async (route: Route) => {
23+
await route.fulfill({
24+
body: responseBody,
25+
status: responseStatusCode
26+
});
27+
});
28+
}
29+
30+
/**
31+
* Add mocking rule to respond with desired status code and payload
32+
* @param {string} mockKey - memory key to get mock instance
33+
* @param {string} statusCode - status code
34+
* @param {string} body - response body
35+
* @example
36+
* When I create mock for '/yourservice/**' with filter options as 'myServiceMock'
37+
* And I set '$myServiceMock' mock to respond '200' with:
38+
* """
39+
* {
40+
* "status": "success"
41+
* }
42+
* """
43+
*/
44+
When('I set {string} mock to respond {string} with:', respondWith);
45+
46+
/**
47+
* Add mocking rule to respond with desired status code and payload
48+
* @param {string} mockKey - memory key to get mock instance
49+
* @param {string} statusCode - status code
50+
* @param {string} body - response body
51+
* @example
52+
* When I create mock for '/yourservice/**' with filter options as 'myServiceMock'
53+
* And I set '$myServiceMock' mock to respond '200' with '$response'
54+
*/
55+
When('I set {string} mock to respond {string} with {string}', respondWith);
56+
57+
/**
58+
* Add mocking rule to abort request with certain reason
59+
* @param {string} mockKey - memory key to get mock instance
60+
* @param {string} reason - reason string see https://playwright.dev/docs/api/class-route#route-abort
61+
* @example
62+
* When I create mock for '/yourservice/**' with filter options as 'myServiceMock'
63+
* And I set '$myServiceMock' mock to abort with 'Failed' reason
64+
*/
65+
When('I set {string} mock to abort with {string} reason', async function (mockKey: string, reason: string) {
66+
const mockUrl: string = await getValue(mockKey);
67+
const errorCode: string = await getValue(reason);
68+
await page.route(mockUrl, async (route: Route) => {
69+
await route.abort(errorCode);
70+
});
71+
});
72+
73+
/**
74+
* Restore mock
75+
* @param {string} mockKey - memory key to get mock instance
76+
* @example When I restore '$myServiceMock'
77+
*/
78+
When('I restore {string} mock', async function (mockKey: string) {
79+
const mockUrl: string = await getValue(mockKey);
80+
await page.unroute(mockUrl);
81+
});
82+
83+
/**
84+
* Restore all mocks
85+
* @example When I restore all mocks
86+
*/
87+
When('I restore all mocks', async function () {
88+
//@ts-ignore
89+
page._routes = [];
90+
});

test-e2e/apps/mock.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Actions</title>
6+
</head>
7+
<body>
8+
<ul id="users">
9+
10+
</ul>
11+
12+
<script>
13+
async function renderUsers() {
14+
const list = document.querySelector('#users');
15+
try {
16+
const response = await fetch('https://jsonplaceholder.typicode.com/users');
17+
const data = await response.json();
18+
data.forEach(user => {
19+
const li = document.createElement('li');
20+
li.innerText = user.name;
21+
list.appendChild(li);
22+
})
23+
} catch (err) {
24+
console.log(err)
25+
const li = document.createElement('li');
26+
li.innerText = err.message;
27+
list.appendChild(li);
28+
}
29+
}
30+
renderUsers();
31+
</script>
32+
</body>
33+
</html>

test-e2e/features/memory.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Feature: Memory
1+
Feature: memory
22

33
Background:
44
When I open '$valuesPage' url

test-e2e/features/mock.feature

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Feature: mock
2+
3+
Background:
4+
Given I restore all mocks
5+
6+
Scenario: mock response multiline
7+
When I create mock for '**/users' as 'usersService'
8+
And I set '$usersService' mock to respond '200' with:
9+
"""
10+
[
11+
{"name": "Mock 1"},
12+
{"name": "Mock 2"},
13+
{"name": "{$userFromMemory}"}
14+
]
15+
"""
16+
And I open '$mockPage' url
17+
Then I expect text of '#1 of Users' to be equal 'Mock 1'
18+
And I expect text of '#2 of Users' to be equal 'Mock 2'
19+
And I expect text of '#3 of Users' to be equal 'Mock 3'
20+
21+
Scenario: mock response from memory
22+
When I create mock for '**/users' as 'usersService'
23+
And I set '$usersService' mock to respond '200' with '$users'
24+
And I open '$mockPage' url
25+
Then I expect text of '#1 of Users' to be equal 'Memory Mock 1'
26+
And I expect text of '#2 of Users' to be equal 'Memory Mock 2'
27+
And I expect text of '#3 of Users' to be equal 'Memory Mock 3'
28+
29+
Scenario: mock abort
30+
When I create mock for '**/users' as 'usersService'
31+
And I set '$usersService' mock to abort with 'failed' reason
32+
And I open '$mockPage' url
33+
Then I expect text of '#1 of Users' to be equal 'Failed to fetch'

test-e2e/memory/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export default class Memory {
55
actionsPage = file(resolve('./test-e2e/apps/actions.html'));
66
framePage = file(resolve('./test-e2e/apps/frame.html'));
77
waitsPage = file(resolve('./test-e2e/apps/waits.html'));
8+
mockPage = file(resolve('./test-e2e/apps/mock.html'));
89

910
array = (...args: Array<any>) => args;
1011

@@ -19,5 +20,13 @@ export default class Memory {
1920

2021
// @ts-ignore
2122
getInnerText = target => target.innerText;
23+
24+
userFromMemory = 'Mock 3';
25+
26+
users = JSON.stringify([
27+
{"name": "Memory Mock 1"},
28+
{"name": "Memory Mock 2"},
29+
{"name": "Memory Mock 3"}
30+
]);
2231
}
2332

test-e2e/page_object/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ export default class App {
2323
Loading = $('#loading');
2424
LoadingInput = $('#loadingInput');
2525
WaitCollection = $$('#waitCollection > div');
26+
27+
Users = $$('#users > li');
2628
}

0 commit comments

Comments
 (0)