Skip to content

Commit 9634b39

Browse files
authored
fix(express): updates the contrnt-length header for req.body (#40)
Signed-off-by: re-Tick <jain.ritik.1001@gmail.com>
1 parent 9490f3f commit 9634b39

22 files changed

+4481
-3806
lines changed

integrations/express/middleware.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
12
import express from "express";
2-
import Keploy from "../../src/keploy";
3+
import Keploy, { HTTP } from "../../src/keploy";
34
import { Request, Response, NextFunction } from "express";
45
import { createExecutionContext, getExecutionContext } from "../../src/context";
56
import { StrArr } from "../../proto/services/StrArr";
@@ -139,13 +140,26 @@ export function afterMiddleware(keploy: Keploy, req: Request, res: Response) {
139140
}
140141

141142
// req.headers
143+
// Since, JSON.stingify trims spaces. Therefore, content-length of request header should be updated
144+
req.headers["content-length"] = JSON.stringify(
145+
JSON.stringify(req.body).length
146+
);
142147
const reqHeader: { [key: string]: StrArr } = getRequestHeader(req.headers);
143148

144149
// response headers
145150
const respHeader: { [key: string]: StrArr } = getResponseHeader(
146151
res.getHeaders()
147152
);
148153

154+
// eslint-disable-next-line prefer-const
155+
let kctx = getExecutionContext(),
156+
deps = undefined,
157+
mocks = undefined;
158+
if (kctx !== undefined && kctx.context !== undefined) {
159+
deps = kctx.context.deps;
160+
mocks = kctx.context.mocks;
161+
}
162+
149163
keploy.capture({
150164
Captured: Date.now(),
151165
AppID: keploy.appConfig.name,
@@ -164,9 +178,10 @@ export function afterMiddleware(keploy: Keploy, req: Request, res: Response) {
164178
// @ts-ignore
165179
Body: String(ResponseBody.get(req)),
166180
},
167-
Dependency: getExecutionContext().context.deps,
181+
Dependency: deps,
168182
TestCasePath: keploy.appConfig.testCasePath,
169183
MockPath: keploy.appConfig.mockPath,
170-
Mocks: getExecutionContext().context.mocks,
184+
Mocks: mocks,
185+
Type: HTTP,
171186
});
172187
}

integrations/node-fetch/require.ts

Lines changed: 131 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,159 +1,157 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
// @ts-ignore
33
import Hook from "require-in-the-middle";
4-
import { Headers,ResponseInit } from "node-fetch";
4+
import { Headers, ResponseInit } from "node-fetch";
55
import mixin from "merge-descriptors";
66
import { getExecutionContext } from "../../src/context";
77
import { Readable } from "stream";
88
import { ProcessDep, stringToBinary } from "../../src/util";
99
import { putMocks } from "../../mock/utils";
10-
import { HTTP_EXPORT, V1_BETA1 } from "../../src/keploy";
10+
import { HTTP, V1_BETA2 } from "../../src/keploy";
1111
import { getRequestHeader, getResponseHeader } from "../express/middleware";
1212
import { getReasonPhrase } from "http-status-codes";
1313
import { DataBytes } from "../../proto/services/DataBytes";
1414
import { MockIds } from "../../mock/mock";
1515

1616
// @ts-ignore
1717
Hook(["node-fetch"], function (exported) {
18-
const wrappedFetch = wrappedNodeFetch(exported);
19-
exported = wrappedFetch
20-
return exported;
18+
const wrappedFetch = wrappedNodeFetch(exported);
19+
exported = wrappedFetch;
20+
return exported;
2121
});
2222

23-
2423
function getHeadersInit(headers: { [k: string]: string[] }): {
25-
[k: string]: string;
26-
} {
27-
const result: { [key: string]: string } = {};
28-
for (const key in headers) {
29-
result[key] = headers[key].join(", ");
30-
}
31-
return result;
24+
[k: string]: string;
25+
} {
26+
const result: { [key: string]: string } = {};
27+
for (const key in headers) {
28+
result[key] = headers[key].join(", ");
3229
}
30+
return result;
31+
}
3332

34-
export function wrappedNodeFetch(fetch:any) {
35-
const fetchFunc = fetch;
36-
async function wrappedFetch(
37-
this: { fetch: (url: any, options: any) => any },
38-
url: any,
39-
options: any
33+
export function wrappedNodeFetch(fetch: any) {
34+
const fetchFunc = fetch;
35+
async function wrappedFetch(
36+
this: { fetch: (url: any, options: any) => any },
37+
url: any,
38+
options: any
39+
) {
40+
if (
41+
getExecutionContext() == undefined ||
42+
getExecutionContext().context == undefined
4043
) {
41-
if (
42-
getExecutionContext() == undefined ||
43-
getExecutionContext().context == undefined
44-
) {
45-
console.error("keploy context is not present to mock dependencies");
46-
return;
47-
}
48-
const ctx = getExecutionContext().context;
49-
let resp = new fetch.Response();
50-
let rinit: ResponseInit = {};
51-
const meta = {
52-
name: "node-fetch",
53-
url: url,
54-
options: options,
55-
type: "HTTP_CLIENT",
56-
};
57-
switch (ctx.mode) {
58-
case "record":
59-
resp = await fetchFunc.apply(this, [url, options]);
60-
const clonedResp = resp.clone();
61-
rinit = {
62-
headers: getHeadersInit(clonedResp.headers.raw()),
63-
status: resp.status,
64-
statusText: resp.statusText,
65-
};
66-
const respData: Buffer[] = [];
67-
clonedResp?.body?.on("data", function (chunk: Buffer) {
68-
respData.push(chunk);
69-
});
70-
clonedResp?.body?.on("end", async function () {
71-
const httpMock = {
72-
Version: V1_BETA1,
73-
Name: ctx.testId,
74-
Kind: HTTP_EXPORT,
75-
Spec: {
76-
Metadata: meta,
77-
Req: {
78-
URL: url,
79-
Body: JSON.stringify(options?.body),
80-
Header: getRequestHeader(options?.headers),
81-
Method: options?.method,
82-
// URLParams:
83-
},
84-
Res: {
85-
StatusCode: rinit.status,
86-
Header: getResponseHeader(rinit.headers),
87-
Body: respData.toString(),
88-
},
44+
console.error("keploy context is not present to mock dependencies");
45+
return;
46+
}
47+
const ctx = getExecutionContext().context;
48+
let resp = new fetch.Response();
49+
let rinit: ResponseInit = {};
50+
const meta = {
51+
name: "node-fetch",
52+
url: url,
53+
options: options,
54+
type: "HTTP_CLIENT",
55+
};
56+
switch (ctx.mode) {
57+
case "record":
58+
resp = await fetchFunc.apply(this, [url, options]);
59+
const clonedResp = resp.clone();
60+
rinit = {
61+
headers: getHeadersInit(clonedResp.headers.raw()),
62+
status: resp.status,
63+
statusText: resp.statusText,
64+
};
65+
const respData: Buffer[] = [];
66+
clonedResp?.body?.on("data", function (chunk: Buffer) {
67+
respData.push(chunk);
68+
});
69+
clonedResp?.body?.on("end", async function () {
70+
const httpMock = {
71+
Version: V1_BETA2,
72+
Name: ctx.testId,
73+
Kind: HTTP,
74+
Spec: {
75+
Metadata: meta,
76+
Req: {
77+
URL: url,
78+
Body: JSON.stringify(options?.body),
79+
Header: getRequestHeader(options?.headers),
80+
Method: options?.method,
81+
// URLParams:
82+
},
83+
Res: {
84+
StatusCode: rinit.status,
85+
Header: getResponseHeader(rinit.headers),
86+
Body: respData.toString(),
8987
},
90-
};
91-
// record mocks for unit-test-mock-library
92-
if (ctx.fileExport === true) {
93-
MockIds[ctx.testId] !== true ? putMocks(httpMock) : "";
94-
} else {
95-
ctx.mocks.push(httpMock);
96-
// ProcessDep(meta, [respData, rinit]);
97-
const res: DataBytes[] = [];
98-
// for (let i = 0; i < outputs.length; i++) {
99-
res.push({ Bin: stringToBinary(JSON.stringify(respData)) });
100-
res.push({ Bin: stringToBinary(JSON.stringify(rinit)) });
101-
// }
102-
ctx.deps.push({
103-
Name: meta.name,
104-
Type: meta.type,
105-
Meta: meta,
106-
Data: res,
107-
});
108-
}
109-
});
110-
break;
111-
case "test":
112-
const outputs = new Array(2);
113-
if (
114-
ctx.mocks != undefined &&
115-
ctx.mocks.length > 0 &&
116-
ctx.mocks[0].Kind == HTTP_EXPORT
117-
) {
118-
const header: { [key: string]: string[] } = {};
119-
for (const k in ctx.mocks[0].Spec?.Res?.Header) {
120-
header[k] = ctx.mocks[0].Spec?.Res?.Header[k]?.Value;
121-
}
122-
outputs[1] = {
123-
headers: getHeadersInit(header),
124-
status: ctx.mocks[0].Spec.Res.StatusCode,
125-
statusText: getReasonPhrase(ctx.mocks[0].Spec.Res.StatusCode),
126-
};
127-
outputs[0] = [ctx.mocks[0].Spec.Res.Body];
128-
if (ctx?.fileExport) {
129-
console.log(
130-
"🤡 Returned the mocked outputs for Http dependency call with meta: ",
131-
meta
132-
);
133-
}
134-
ctx.mocks.shift();
88+
},
89+
};
90+
// record mocks for unit-test-mock-library
91+
if (ctx.fileExport === true) {
92+
MockIds[ctx.testId] !== true ? putMocks(httpMock) : "";
13593
} else {
136-
ProcessDep({}, outputs);
94+
ctx.mocks.push(httpMock);
95+
// ProcessDep(meta, [respData, rinit]);
96+
const res: DataBytes[] = [];
97+
// for (let i = 0; i < outputs.length; i++) {
98+
res.push({ Bin: stringToBinary(JSON.stringify(respData)) });
99+
res.push({ Bin: stringToBinary(JSON.stringify(rinit)) });
100+
// }
101+
ctx.deps.push({
102+
Name: meta.name,
103+
Type: meta.type,
104+
Meta: meta,
105+
Data: res,
106+
});
107+
}
108+
});
109+
break;
110+
case "test":
111+
const outputs = new Array(2);
112+
if (
113+
ctx.mocks != undefined &&
114+
ctx.mocks.length > 0 &&
115+
ctx.mocks[0].Kind == HTTP
116+
) {
117+
const header: { [key: string]: string[] } = {};
118+
for (const k in ctx.mocks[0].Spec?.Res?.Header) {
119+
header[k] = ctx.mocks[0].Spec?.Res?.Header[k]?.Value;
120+
}
121+
outputs[1] = {
122+
headers: getHeadersInit(header),
123+
status: ctx.mocks[0].Spec.Res.StatusCode,
124+
statusText: getReasonPhrase(ctx.mocks[0].Spec.Res.StatusCode),
125+
};
126+
outputs[0] = [ctx.mocks[0].Spec.Res.Body];
127+
if (ctx?.fileExport) {
128+
console.log(
129+
"🤡 Returned the mocked outputs for Http dependency call with meta: ",
130+
meta
131+
);
137132
}
138-
rinit.headers = new Headers(outputs[1].headers);
139-
rinit.status = outputs[1].status;
140-
rinit.statusText = outputs[1].statusText;
141-
const buf: Buffer[] = [];
142-
outputs[0].map((el: any) => {
143-
buf.push(Buffer.from(el));
144-
});
145-
resp = new fetch.Response(Readable.from(buf), rinit);
146-
break;
147-
case "off":
148-
return fetchFunc.apply(this, [url, options]);
149-
default:
150-
console.debug(
151-
"mode is not valid. Please set valid keploy mode using env variables"
152-
);
153-
return fetchFunc.apply(this, [url, options]);
154-
}
155-
return resp;
133+
ctx.mocks.shift();
134+
} else {
135+
ProcessDep({}, outputs);
136+
}
137+
rinit.headers = new Headers(outputs[1].headers);
138+
rinit.status = outputs[1].status;
139+
rinit.statusText = outputs[1].statusText;
140+
const buf: Buffer[] = [];
141+
outputs[0].map((el: any) => {
142+
buf.push(Buffer.from(el));
143+
});
144+
resp = new fetch.Response(Readable.from(buf), rinit);
145+
break;
146+
case "off":
147+
return fetchFunc.apply(this, [url, options]);
148+
default:
149+
console.debug(
150+
"mode is not valid. Please set valid keploy mode using env variables"
151+
);
152+
return fetchFunc.apply(this, [url, options]);
156153
}
157-
return mixin(wrappedFetch, fetchFunc, false);
154+
return resp;
158155
}
159-
156+
return mixin(wrappedFetch, fetchFunc, false);
157+
}

integrations/octokit/require.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getExecutionContext } from "../../src/context";
77
import { Readable } from "stream";
88
import { ProcessDep, stringToBinary } from "../../src/util";
99
import { putMocks } from "../../mock/utils";
10-
import { HTTP_EXPORT, V1_BETA1 } from "../../src/keploy";
10+
import { HTTP, V1_BETA2 } from "../../src/keploy";
1111
import { getRequestHeader, getResponseHeader } from "../express/middleware";
1212
import { getReasonPhrase } from "http-status-codes";
1313
import { DataBytes } from "../../proto/services/DataBytes";
@@ -124,9 +124,9 @@ export function wrappedNodeFetch(fetchFunc: Function) {
124124
});
125125
clonedResp?.body?.on("end", async function () {
126126
const httpMock = {
127-
Version: V1_BETA1,
127+
Version: V1_BETA2,
128128
Name: ctx.testId,
129-
Kind: HTTP_EXPORT,
129+
Kind: HTTP,
130130
Spec: {
131131
Metadata: meta,
132132
Req: {
@@ -168,7 +168,7 @@ export function wrappedNodeFetch(fetchFunc: Function) {
168168
if (
169169
ctx.mocks != undefined &&
170170
ctx.mocks.length > 0 &&
171-
ctx.mocks[0].Kind == HTTP_EXPORT
171+
ctx.mocks[0].Kind == HTTP
172172
) {
173173
const header: { [key: string]: string[] } = {};
174174
for (const k in ctx.mocks[0].Spec?.Res?.Header) {

0 commit comments

Comments
 (0)