Repository navigation
Expand file tree
/
Copy pathtopic.test.ts
More file actions
124 lines (101 loc) · 4.83 KB
/
Copy pathtopic.test.ts
File metadata and controls
124 lines (101 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { strict as assert } from "node:assert";
import { existsSync } from "node:fs";
import { join } from "node:path";
import { describe, it } from "node:test";
import { resolveTopic, safeStem, scalarOrUndefined } from "./topic";
describe("resolveTopic", () => {
it("resolves a plain key", () => {
assert.equal(resolveTopic({ event: "charge.succeeded" }, "event"), "charge.succeeded");
});
it("resolves a dotted path", () => {
assert.equal(resolveTopic({ data: { type: "invoice.paid" } }, "data.type"), "invoice.paid");
});
it("resolves an array segment using the first element", () => {
const body = { events: [{ eventType: "user.created" }, { eventType: "user.deleted" }] };
assert.equal(resolveTopic(body, "events[].eventType"), "user.created");
});
it("resolves nested array segments", () => {
const body = { entry: [{ changes: [{ field: "messages" }] }] };
assert.equal(resolveTopic(body, "entry[].changes[].field"), "messages");
});
it("resolves an array segment nested under a dotted path", () => {
const body = { data: { events: [{ eventType: "user.lifecycle.activate" }] } };
assert.equal(resolveTopic(body, "data.events[].eventType"), "user.lifecycle.activate");
});
it("resolves a top-level array when the segment name before [] is empty", () => {
const body = [{ type: "qbo.account.created.v1" }, { type: "qbo.account.updated.v1" }];
assert.equal(resolveTopic(body, "[].type"), "qbo.account.created.v1");
});
it("returns undefined for [] when the body is not an array", () => {
assert.equal(resolveTopic({ type: "x" }, "[].type"), undefined);
});
// A header called "x-thing.type" is a real key, not a path into "x-thing".
it("prefers a literal key over interpreting it as a path", () => {
const headers = { "data.type": "literal", data: { type: "viaPath" } };
assert.equal(resolveTopic(headers, "data.type"), "literal");
});
it("returns undefined when the path lands on an object", () => {
assert.equal(resolveTopic({ data: { type: { nested: true } } }, "data.type"), undefined);
});
it("returns undefined when an array segment finds no array", () => {
assert.equal(resolveTopic({ events: { eventType: "x" } }, "events[].eventType"), undefined);
});
it("returns undefined for an empty array", () => {
assert.equal(resolveTopic({ events: [] }, "events[].eventType"), undefined);
});
it("returns undefined when the path breaks part way", () => {
assert.equal(resolveTopic({ data: null }, "data.type"), undefined);
assert.equal(resolveTopic({}, "a.b.c"), undefined);
});
it("returns undefined for a null or undefined source", () => {
assert.equal(resolveTopic(null, "event"), undefined);
assert.equal(resolveTopic(undefined, "event"), undefined);
});
it("coerces a numeric value to a string", () => {
assert.equal(resolveTopic({ data: { type: 42 } }, "data.type"), "42");
});
});
describe("scalarOrUndefined", () => {
it("passes through strings and stringifies numbers", () => {
assert.equal(scalarOrUndefined("a"), "a");
assert.equal(scalarOrUndefined(0), "0");
});
it("rejects anything that would stringify to [object Object]", () => {
assert.equal(scalarOrUndefined({}), undefined);
assert.equal(scalarOrUndefined([]), undefined);
assert.equal(scalarOrUndefined(null), undefined);
assert.equal(scalarOrUndefined(undefined), undefined);
assert.equal(scalarOrUndefined(true), undefined);
});
});
// Each case is a topic whose doc sample is already in providers/ under the registry's
// stem, so a capture of the same event has to be written to that same file.
describe("safeStem", () => {
const cases: [string, string, string][] = [
["pubnub/latest", "pubnub.com/schemas/events/channel.created?v=1.0.0",
"pubnub.com.schemas.events.channel.created.v.1.0.0"],
["mailtrap/latest", "soft bounce", "soft.bounce"],
["descope/latest", "Change Password", "Change.Password"],
["document360/latest", "Extension token deleted", "Extension.token.deleted"],
["flexport/latest", "/shipment_leg#departed", "shipment_leg.departed"],
["castle/v1", "$list_item.created", "list_item.created"],
];
for (const [dir, topic, stem] of cases) {
it(`names ${JSON.stringify(topic)} as the registry does (${dir}/${stem}.json)`, () => {
assert.equal(safeStem(topic), stem);
assert.ok(existsSync(join(__dirname, "providers", dir, `${stem}.json`)));
});
}
it("collapses a run of unsafe characters into one dot", () => {
assert.equal(safeStem("a :/\\ b"), "a.b");
});
it("keeps dots, dashes and underscores", () => {
assert.equal(safeStem("charge.succeeded_v-2"), "charge.succeeded_v-2");
});
it("strips leading and trailing dots", () => {
assert.equal(safeStem("..a.."), "a");
});
it("never returns an empty stem", () => {
assert.equal(safeStem("///"), "_unnamed");
});
});