Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Current
## 0.0.8
- :beetle: fixed issue that opens page from browser, not from context
- :rocket: added mock steps

## 0.0.7
- :rocket: added capability to connect via CDP
Expand Down
90 changes: 90 additions & 0 deletions src/mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { When } from '@cucumber/cucumber';
import { getValue } from './transformers';
import memory from '@qavajs/memory';
import { Route } from '@playwright/test';

/**
* Create simple mock instance
* @param {string} urlTemplate - minimatch url template to mock
* @param {string} memoryKey - memory key to store mock instance
* @example When I create mock for '/yourservice/**' as 'mock1'
* @example When I create mock for '$mockUrlTemplate' as 'mock1'
*/
When('I create mock for {string} as {string}', async function (urlTemplate: string, memoryKey: string) {
const url = await getValue(urlTemplate);
memory.setValue(memoryKey, url);
});

async function respondWith(mockKey: string, statusCode: string, body: string): Promise<void> {
const mockUrl: string = await getValue(mockKey);
const responseStatusCode: number = parseInt(await getValue(statusCode));
const responseBody = await getValue(body);
await page.route(mockUrl, async (route: Route) => {
await route.fulfill({
body: responseBody,
status: responseStatusCode
});
});
}

/**
* Add mocking rule to respond with desired status code and payload
* @param {string} mockKey - memory key to get mock instance
* @param {string} statusCode - status code
* @param {string} body - response body
* @example
* When I create mock for '/yourservice/**' with filter options as 'myServiceMock'
* And I set '$myServiceMock' mock to respond '200' with:
* """
* {
* "status": "success"
* }
* """
*/
When('I set {string} mock to respond {string} with:', respondWith);

/**
* Add mocking rule to respond with desired status code and payload
* @param {string} mockKey - memory key to get mock instance
* @param {string} statusCode - status code
* @param {string} body - response body
* @example
* When I create mock for '/yourservice/**' with filter options as 'myServiceMock'
* And I set '$myServiceMock' mock to respond '200' with '$response'
*/
When('I set {string} mock to respond {string} with {string}', respondWith);

/**
* Add mocking rule to abort request with certain reason
* @param {string} mockKey - memory key to get mock instance
* @param {string} reason - reason string see https://playwright.dev/docs/api/class-route#route-abort
* @example
* When I create mock for '/yourservice/**' with filter options as 'myServiceMock'
* And I set '$myServiceMock' mock to abort with 'Failed' reason
*/
When('I set {string} mock to abort with {string} reason', async function (mockKey: string, reason: string) {
const mockUrl: string = await getValue(mockKey);
const errorCode: string = await getValue(reason);
await page.route(mockUrl, async (route: Route) => {
await route.abort(errorCode);
});
});

/**
* Restore mock
* @param {string} mockKey - memory key to get mock instance
* @example When I restore '$myServiceMock'
*/
When('I restore {string} mock', async function (mockKey: string) {
const mockUrl: string = await getValue(mockKey);
await page.unroute(mockUrl);
});

/**
* Restore all mocks
* @example When I restore all mocks
*/
When('I restore all mocks', async function () {
//@ts-ignore
page._routes = [];
});
33 changes: 33 additions & 0 deletions test-e2e/apps/mock.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Actions</title>
</head>
<body>
<ul id="users">

</ul>

<script>
async function renderUsers() {
const list = document.querySelector('#users');
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
data.forEach(user => {
const li = document.createElement('li');
li.innerText = user.name;
list.appendChild(li);
})
} catch (err) {
console.log(err)
const li = document.createElement('li');
li.innerText = err.message;
list.appendChild(li);
}
}
renderUsers();
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion test-e2e/features/memory.feature
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Feature: Memory
Feature: memory

Background:
When I open '$valuesPage' url
Expand Down
33 changes: 33 additions & 0 deletions test-e2e/features/mock.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Feature: mock

Background:
Given I restore all mocks

Scenario: mock response multiline
When I create mock for '**/users' as 'usersService'
And I set '$usersService' mock to respond '200' with:
"""
[
{"name": "Mock 1"},
{"name": "Mock 2"},
{"name": "{$userFromMemory}"}
]
"""
And I open '$mockPage' url
Then I expect text of '#1 of Users' to be equal 'Mock 1'
And I expect text of '#2 of Users' to be equal 'Mock 2'
And I expect text of '#3 of Users' to be equal 'Mock 3'

Scenario: mock response from memory
When I create mock for '**/users' as 'usersService'
And I set '$usersService' mock to respond '200' with '$users'
And I open '$mockPage' url
Then I expect text of '#1 of Users' to be equal 'Memory Mock 1'
And I expect text of '#2 of Users' to be equal 'Memory Mock 2'
And I expect text of '#3 of Users' to be equal 'Memory Mock 3'

Scenario: mock abort
When I create mock for '**/users' as 'usersService'
And I set '$usersService' mock to abort with 'failed' reason
And I open '$mockPage' url
Then I expect text of '#1 of Users' to be equal 'Failed to fetch'
9 changes: 9 additions & 0 deletions test-e2e/memory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default class Memory {
actionsPage = file(resolve('./test-e2e/apps/actions.html'));
framePage = file(resolve('./test-e2e/apps/frame.html'));
waitsPage = file(resolve('./test-e2e/apps/waits.html'));
mockPage = file(resolve('./test-e2e/apps/mock.html'));

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

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

// @ts-ignore
getInnerText = target => target.innerText;

userFromMemory = 'Mock 3';

users = JSON.stringify([
{"name": "Memory Mock 1"},
{"name": "Memory Mock 2"},
{"name": "Memory Mock 3"}
]);
}

2 changes: 2 additions & 0 deletions test-e2e/page_object/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ export default class App {
Loading = $('#loading');
LoadingInput = $('#loadingInput');
WaitCollection = $$('#waitCollection > div');

Users = $$('#users > li');
}