playwright-fluent
Version:
Fluent API around playwright
200 lines (199 loc) • 7.72 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.withMocks = exports.spreadMissingProperties = exports.inferMockResponseTypeIfNeeded = exports.getMockStatus = exports.defaultMocksOptions = exports.passthroughMock = exports.getPostDataOf = exports.noopVoidFunc = void 0;
const utils_1 = require("../../../utils");
function noopVoidFunc() {
// do nothing
}
exports.noopVoidFunc = noopVoidFunc;
function getPostDataOf(request) {
try {
return request.postDataJSON();
}
catch (error) {
return request.postData();
}
}
exports.getPostDataOf = getPostDataOf;
exports.passthroughMock = {
displayName: 'passthroughMock',
urlMatcher: () => true,
methodMatcher: () => true,
queryStringMatcher: () => true,
postDataMatcher: () => true,
contextMatcher: () => true,
customMatcher: () => true,
enrichResponseHeaders: (headers) => headers,
responseType: 'continue',
status: 200,
jsonResponse: () => {
return {};
},
rawResponse: () => '',
delayInMilliseconds: 0,
updateData: noopVoidFunc,
lastUpdated: () => new Date(),
updatePolicy: 'always',
};
exports.defaultMocksOptions = {
// eslint-disable-next-line @typescript-eslint/no-empty-function
onMockNotFound: () => { },
// eslint-disable-next-line @typescript-eslint/no-empty-function
onMockFound: () => { },
// eslint-disable-next-line @typescript-eslint/no-empty-function
onInternalError: () => { },
};
function getMockStatus(mock, requestInfos) {
if (typeof mock.status === 'function') {
return mock.status(requestInfos);
}
if (typeof mock.status === 'number') {
return mock.status;
}
return 200;
}
exports.getMockStatus = getMockStatus;
function inferMockResponseTypeIfNeeded(mock) {
if (mock.responseType) {
return mock;
}
if (typeof mock.jsonResponse === 'function' && typeof mock.rawResponse !== 'function') {
return {
...mock,
responseType: 'json',
};
}
if (typeof mock.rawResponse === 'function' && typeof mock.jsonResponse !== 'function') {
return {
...mock,
responseType: 'string',
};
}
if (typeof mock.rawResponse !== 'function' && typeof mock.jsonResponse !== 'function') {
return {
...mock,
responseType: 'empty',
};
}
return mock;
}
exports.inferMockResponseTypeIfNeeded = inferMockResponseTypeIfNeeded;
function spreadMissingProperties(mock) {
return { ...exports.passthroughMock, displayName: 'not set', ...mock };
}
exports.spreadMissingProperties = spreadMissingProperties;
async function fullfillRouteWithMock(mock, route, options) {
if (mock.delayInMilliseconds > 0) {
setTimeout(() => route.fulfill(options), mock.delayInMilliseconds);
return;
}
route.fulfill(options);
}
async function withMocks(mocks, context, options, page) {
if (typeof mocks !== 'function') {
throw new Error(`mocks must be a function that returns an array of FluentMock objects.`);
}
if (!Array.isArray(mocks())) {
throw new Error(`mocks must be a function that returns an array of FluentMock objects.`);
}
if (!page) {
throw new Error(`Cannot intercept requests with mocks because no browser has been launched`);
}
const mockOptions = {
...exports.defaultMocksOptions,
...options,
};
await page.route((uri) => {
if (mocks().length === 0) {
return false;
}
const mockExists = mocks()
.map(inferMockResponseTypeIfNeeded)
.map(spreadMissingProperties)
.map((mock) => mock.urlMatcher(uri.toString()))
.some((match) => match === true);
return mockExists;
}, (route, request) => {
const requestMethod = request.method();
const url = request.url();
const queryString = (0, utils_1.extractQueryStringObjectFromUrl)(url);
const postData = getPostDataOf(request);
const sharedContext = context();
const requestInfos = { request, queryString, postData, sharedContext };
const mock = mocks()
.map(inferMockResponseTypeIfNeeded)
.map(spreadMissingProperties)
.filter((mock) => mock.urlMatcher(url))
.filter((mock) => mock.methodMatcher(requestMethod))
.filter((mock) => mock.queryStringMatcher(queryString))
.filter((mock) => mock.postDataMatcher(postData))
.filter((mock) => mock.contextMatcher(sharedContext))
.filter((mock) => mock.customMatcher(requestInfos))
.pop();
if (!mock) {
mockOptions.onMockNotFound(requestInfos);
route.continue();
return;
}
if (mock.responseType === 'continue' && mock.delayInMilliseconds === 0) {
route.continue();
return;
}
if (mock.responseType === 'continue' && mock.delayInMilliseconds > 0) {
setTimeout(() => route.continue(), mock.delayInMilliseconds);
return;
}
if (mock.responseType === 'json') {
const responseObject = mock.jsonResponse(requestInfos);
const headers = mock.enrichResponseHeaders({
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
});
const status = getMockStatus(mock, requestInfos);
const body = JSON.stringify(responseObject);
const contentType = 'application/json';
mockOptions.onMockFound(mock, requestInfos);
fullfillRouteWithMock(mock, route, { status, headers, contentType, body });
return;
}
if (mock.responseType === 'string') {
const headers = mock.enrichResponseHeaders({
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
});
const status = getMockStatus(mock, requestInfos);
const body = mock.rawResponse(requestInfos);
const contentType = 'text/plain';
mockOptions.onMockFound(mock, requestInfos);
fullfillRouteWithMock(mock, route, { status, headers, contentType, body });
return;
}
if (mock.responseType === 'empty') {
const headers = mock.enrichResponseHeaders({
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
});
const status = getMockStatus(mock, requestInfos);
const body = '';
const contentType = 'text/plain';
mockOptions.onMockFound(mock, requestInfos);
fullfillRouteWithMock(mock, route, { status, headers, contentType, body });
return;
}
if (mock.responseType === 'javascript') {
const headers = mock.enrichResponseHeaders({
'access-control-allow-methods': '*',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
});
const status = getMockStatus(mock, requestInfos);
const body = mock.rawResponse(requestInfos);
const contentType = 'application/javascript';
mockOptions.onMockFound(mock, requestInfos);
fullfillRouteWithMock(mock, route, { status, headers, contentType, body });
return;
}
throw new Error(`mock with response type '${mock.responseType}' is not yet implemented`);
});
}
exports.withMocks = withMocks;
;