Skip to content

Commit b8d3871

Browse files
committed
WIP - add segment middleware test
1 parent 698e6c9 commit b8d3871

File tree

6 files changed

+188
-9
lines changed

6 files changed

+188
-9
lines changed

.metals/metals.lock.db

-6
This file was deleted.

package-lock.json

+18-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/chatbot-server-mongodb-public/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"@types/common-tags": "^1.8.1",
5151
"@types/cookie-parser": "^1.4.6",
5252
"@types/express": "^4.17.21",
53+
"@types/express-serve-static-core": "^5.0.6",
5354
"@types/jest": "^29.5.2",
5455
"@typescript-eslint/eslint-plugin": "^5.58.0",
5556
"@typescript-eslint/parser": "^5.58.0",
@@ -59,6 +60,7 @@
5960
"eslint-config-prettier": "^8.8.0",
6061
"eslint-plugin-jest": "^27.2.1",
6162
"jest": "^29.6.1",
63+
"node-mocks-http": "^1.16.2",
6264
"nodemon": "^3.0.1",
6365
"prettier": "^2.8.7",
6466
"readline": "^1.3.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import {
2+
SEGMENT_ANONYMOUS_ID_HEADER,
3+
SEGMENT_USER_ID_HEADER,
4+
useSegmentIds,
5+
} from "./useSegmentIds";
6+
import {
7+
caseInsensitiveHeaders,
8+
createConversationsMiddlewareReq,
9+
createConversationsMiddlewareRes,
10+
} from "../test/middlewareTestHelpers";
11+
12+
const baseReq = {
13+
body: { message: "Hello, world!" },
14+
params: { conversationId: "conversation-1234" },
15+
query: { stream: "true" },
16+
headers: { "req-id": "request-1234" },
17+
ip: "127.0.0.1",
18+
};
19+
20+
describe("useSegmentIds", () => {
21+
it(`sets segmentUserId in customData when the ${SEGMENT_USER_ID_HEADER} header is present`, () => {
22+
const req = createConversationsMiddlewareReq();
23+
const res = createConversationsMiddlewareRes();
24+
const next = jest.fn();
25+
26+
const middleware = useSegmentIds();
27+
req.body = baseReq.body;
28+
req.params = baseReq.params;
29+
req.query = baseReq.query;
30+
req.headers = caseInsensitiveHeaders({
31+
...baseReq.headers,
32+
[SEGMENT_USER_ID_HEADER]: "test-user-id",
33+
});
34+
req.ip = baseReq.ip;
35+
36+
middleware(req, res, next);
37+
38+
expect(res.locals.customData).toMatchObject({
39+
segmentUserId: "test-user-id",
40+
});
41+
expect(next).toHaveBeenCalledTimes(1);
42+
});
43+
44+
it(`does not set segmentUserId in customData when the ${SEGMENT_USER_ID_HEADER} header is not present`, () => {
45+
const req = createConversationsMiddlewareReq();
46+
const res = createConversationsMiddlewareRes();
47+
const next = jest.fn();
48+
49+
const middleware = useSegmentIds();
50+
req.body = baseReq.body;
51+
req.params = baseReq.params;
52+
req.query = baseReq.query;
53+
req.headers = caseInsensitiveHeaders({
54+
...baseReq.headers,
55+
});
56+
57+
middleware(req, res, next);
58+
59+
expect(res.locals.customData).not.toHaveProperty("segmentUserId");
60+
expect(next).toHaveBeenCalledTimes(1);
61+
});
62+
63+
it(`sets segmentAnonymousId in customData when the ${SEGMENT_ANONYMOUS_ID_HEADER} header is present`, () => {
64+
const req = createConversationsMiddlewareReq();
65+
const res = createConversationsMiddlewareRes();
66+
const next = jest.fn();
67+
68+
const middleware = useSegmentIds();
69+
req.body = baseReq.body;
70+
req.params = baseReq.params;
71+
req.query = baseReq.query;
72+
req.headers = caseInsensitiveHeaders({
73+
...baseReq.headers,
74+
[SEGMENT_ANONYMOUS_ID_HEADER]: "test-user-id",
75+
});
76+
req.ip = baseReq.ip;
77+
78+
middleware(req, res, next);
79+
80+
expect(res.locals.customData).toMatchObject({
81+
segmentAnonymousId: "test-user-id",
82+
});
83+
expect(next).toHaveBeenCalledTimes(1);
84+
});
85+
86+
it(`does not set segmentAnonymousId in customData when the ${SEGMENT_ANONYMOUS_ID_HEADER} header is not present`, () => {
87+
const req = createConversationsMiddlewareReq();
88+
const res = createConversationsMiddlewareRes();
89+
const next = jest.fn();
90+
91+
const middleware = useSegmentIds();
92+
req.body = baseReq.body;
93+
req.params = baseReq.params;
94+
req.query = baseReq.query;
95+
req.headers = caseInsensitiveHeaders({
96+
...baseReq.headers,
97+
});
98+
99+
middleware(req, res, next);
100+
101+
expect(res.locals.customData).not.toHaveProperty("segmentAnonymousId");
102+
expect(next).toHaveBeenCalledTimes(1);
103+
});
104+
105+
it("sets both segmentUserId and segmentAnonymousId in customData when both headers are present", () => {
106+
const req = createConversationsMiddlewareReq();
107+
const res = createConversationsMiddlewareRes();
108+
const next = jest.fn();
109+
110+
const middleware = useSegmentIds();
111+
req.body = baseReq.body;
112+
req.params = baseReq.params;
113+
req.query = baseReq.query;
114+
req.headers = caseInsensitiveHeaders({
115+
...baseReq.headers,
116+
[SEGMENT_USER_ID_HEADER]: "test-user-id",
117+
[SEGMENT_ANONYMOUS_ID_HEADER]: "test-anonymous-id",
118+
});
119+
req.ip = baseReq.ip;
120+
121+
middleware(req, res, next);
122+
123+
expect(res.locals.customData).toMatchObject({
124+
segmentUserId: "test-user-id",
125+
segmentAnonymousId: "test-anonymous-id",
126+
});
127+
expect(next).toHaveBeenCalledTimes(1);
128+
});
129+
});

packages/chatbot-server-mongodb-public/src/middleware/useSegmentIds.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ConversationsMiddleware } from "mongodb-chatbot-server";
22

3-
const SEGMENT_USER_ID_HEADER = "X-Segment-User-Id";
4-
const SEGMENT_ANONYMOUS_ID_HEADER = "X-Segment-Anonymous-Id";
3+
export const SEGMENT_USER_ID_HEADER = "X-Segment-User-Id";
4+
export const SEGMENT_ANONYMOUS_ID_HEADER = "X-Segment-Anonymous-Id";
55

66
export function useSegmentIds(): ConversationsMiddleware {
77
return (req, res, next) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Request } from "express";
2+
import { ParamsDictionary } from "express-serve-static-core";
3+
import { createRequest, createResponse } from "node-mocks-http";
4+
import { ConversationsService } from "mongodb-rag-core";
5+
import {
6+
ConversationsRouterLocals,
7+
ConversationsRouterResponse,
8+
} from "mongodb-chatbot-server";
9+
10+
export const createConversationsMiddlewareReq = () =>
11+
createRequest<
12+
Request<
13+
ParamsDictionary,
14+
unknown,
15+
unknown,
16+
unknown,
17+
ConversationsRouterLocals
18+
>
19+
>();
20+
21+
export const createConversationsMiddlewareRes = () => {
22+
const res = createResponse<ConversationsRouterResponse>();
23+
res.locals = {
24+
conversations: {} as unknown as ConversationsService,
25+
customData: {},
26+
};
27+
return res;
28+
};
29+
30+
export function caseInsensitiveHeaders(headers: Record<string, string>) {
31+
// Express automatically converts all headers to lowercase but
32+
// node-mocks-http does not. This function is a workaround for that.
33+
return Object.entries(headers).reduce((acc, [key, value]) => {
34+
acc[key.toLowerCase()] = value;
35+
return acc;
36+
}, {} as Record<string, string>);
37+
}

0 commit comments

Comments
 (0)