request-mocking-protocol
Version:
A protocol for declarative mocking of HTTP requests
130 lines • 4.55 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResponseBuilder = void 0;
/**
* Response builder class.
*/
const node_http_1 = require("node:http");
const utils_1 = require("./utils");
const placeholders_1 = require("./placeholders");
const request_patcher_1 = require("../request-patcher");
class ResponseBuilder {
matchResult;
callbacks;
status = 200;
statusText = 'OK';
headers = new Headers();
body = null;
constructor(matchResult, callbacks) {
this.matchResult = matchResult;
this.callbacks = callbacks;
}
get resSchema() {
return this.matchResult.mockSchema.resSchema;
}
get params() {
return this.matchResult.params;
}
get req() {
return this.matchResult.req;
}
async build() {
if (this.needsRealRequest()) {
await this.setPatchedResponse();
}
else {
this.setStaticResponse();
}
await this.wait();
return {
status: this.status,
statusText: this.statusText,
headers: this.headers,
body: this.body,
};
}
needsRealRequest() {
return this.resSchema.request || this.resSchema.bodyPatch;
}
async setPatchedResponse() {
const res = await this.sendRealRequest();
this.setStatus(res.status, res.statusText);
this.setHeaders(res.headers);
// remove content-encoding header, otherwise error: Decompression failed
this.headers.delete('content-encoding');
await this.setPatchedBody(res);
}
setStaticResponse() {
if (this.resSchema.status)
this.setStatus(this.resSchema.status);
this.setHeaders();
this.setStaticBody();
}
setStatus(status, statusText) {
this.status = status;
this.statusText = statusText || node_http_1.STATUS_CODES[status] || 'Unknown';
}
async sendRealRequest() {
const { request: requestOverrides } = this.resSchema;
const req = requestOverrides
? await new request_patcher_1.RequestPatcher(this.req, requestOverrides, this.params).patch()
: this.req;
return this.callbacks.bypass(req);
}
setHeaders(origHeaders) {
// Important to use Object.fromEntries(), otherwise headers become empty inside msw.
// See: https://github.com/mswjs/msw/blob/main/src/core/utils/HttpResponse/decorators.ts#L20
this.headers = new Headers(Object.fromEntries(origHeaders || []));
Object.entries(this.resSchema.headers || {}).forEach(([key, value]) => {
if (value) {
value = (0, placeholders_1.replacePlaceholders)(value, this.params);
this.headers.set(key, value);
}
else {
this.headers.delete(key);
}
});
}
async setPatchedBody(res) {
const { bodyPatch } = this.resSchema;
if (bodyPatch) {
// todo: match status? If response status is not 200, should we patch it?
// todo: handle parse error
const actualBody = await res.json();
const bodyPatchFinal = (0, placeholders_1.cloneWithPlaceholders)(bodyPatch, this.params);
(0, utils_1.patchObject)(actualBody, bodyPatchFinal);
this.setBodyAsString(JSON.stringify(actualBody), 'application/json');
}
else {
this.body = await res.arrayBuffer();
}
}
setStaticBody() {
const { body } = this.resSchema;
if (!body)
return;
if (typeof body === 'string') {
const newBody = (0, placeholders_1.replacePlaceholders)(body, this.params);
this.setBodyAsString(newBody, 'text/plain');
}
else {
const newBody = (0, placeholders_1.stringifyWithPlaceholders)(body, this.params);
this.setBodyAsString(newBody, 'application/json');
}
}
setBodyAsString(body, contentType) {
this.body = body;
if (!this.headers.has('content-type')) {
this.headers.set('content-type', contentType);
}
const contentLength = body ? new Blob([body]).size.toString() : '0';
this.headers.set('content-length', contentLength);
}
async wait() {
const { delay } = this.resSchema;
if (delay)
await (0, utils_1.wait)(delay);
}
}
exports.ResponseBuilder = ResponseBuilder;
//# sourceMappingURL=index.js.map