@eventvisor/core 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/lib/generate-code/index.js.map +1 -1
  3. package/lib/linter/conditionsSchema.d.ts +1 -301
  4. package/lib/linter/conditionsSchema.js +8 -14
  5. package/lib/linter/conditionsSchema.js.map +1 -1
  6. package/lib/linter/destinationSchema.d.ts +89 -1
  7. package/lib/linter/destinationSchema.js +0 -2
  8. package/lib/linter/destinationSchema.js.map +1 -1
  9. package/lib/linter/effectSchema.d.ts +9 -1209
  10. package/lib/linter/effectSchema.js +6 -3
  11. package/lib/linter/effectSchema.js.map +1 -1
  12. package/lib/linter/entitySchemas.spec.d.ts +1 -0
  13. package/lib/linter/entitySchemas.spec.js +169 -0
  14. package/lib/linter/entitySchemas.spec.js.map +1 -0
  15. package/lib/linter/eventSchema.js +7 -2
  16. package/lib/linter/eventSchema.js.map +1 -1
  17. package/lib/linter/lintProject.d.ts +5 -0
  18. package/lib/linter/lintProject.js +141 -5
  19. package/lib/linter/lintProject.js.map +1 -1
  20. package/lib/linter/lintProject.spec.d.ts +1 -0
  21. package/lib/linter/lintProject.spec.js +103 -0
  22. package/lib/linter/lintProject.spec.js.map +1 -0
  23. package/lib/linter/persistSchema.d.ts +4 -604
  24. package/lib/linter/persistSchema.js +4 -2
  25. package/lib/linter/persistSchema.js.map +1 -1
  26. package/lib/linter/printError.js +4 -0
  27. package/lib/linter/printError.js.map +1 -1
  28. package/lib/linter/sampleSchema.d.ts +13 -285
  29. package/lib/linter/sampleSchema.js +2 -1
  30. package/lib/linter/sampleSchema.js.map +1 -1
  31. package/lib/linter/semanticValidation.d.ts +11 -0
  32. package/lib/linter/semanticValidation.js +592 -0
  33. package/lib/linter/semanticValidation.js.map +1 -0
  34. package/lib/linter/semanticValidation.spec.d.ts +1 -0
  35. package/lib/linter/semanticValidation.spec.js +190 -0
  36. package/lib/linter/semanticValidation.spec.js.map +1 -0
  37. package/lib/linter/testSchema.d.ts +64 -3
  38. package/lib/linter/testSchema.js +81 -4
  39. package/lib/linter/testSchema.js.map +1 -1
  40. package/lib/linter/testSchema.spec.d.ts +1 -0
  41. package/lib/linter/testSchema.spec.js +260 -0
  42. package/lib/linter/testSchema.spec.js.map +1 -0
  43. package/package.json +5 -5
  44. package/src/generate-code/index.ts +2 -0
  45. package/src/linter/conditionsSchema.ts +12 -18
  46. package/src/linter/destinationSchema.ts +0 -3
  47. package/src/linter/effectSchema.ts +12 -9
  48. package/src/linter/entitySchemas.spec.ts +212 -0
  49. package/src/linter/eventSchema.ts +10 -5
  50. package/src/linter/lintProject.spec.ts +112 -0
  51. package/src/linter/lintProject.ts +134 -6
  52. package/src/linter/persistSchema.ts +6 -4
  53. package/src/linter/printError.ts +3 -0
  54. package/src/linter/sampleSchema.ts +3 -1
  55. package/src/linter/semanticValidation.spec.ts +239 -0
  56. package/src/linter/semanticValidation.ts +953 -0
  57. package/src/linter/testSchema.spec.ts +279 -0
  58. package/src/linter/testSchema.ts +89 -4
@@ -0,0 +1,279 @@
1
+ import { getTestSchema } from "./testSchema";
2
+ import type { Dependencies } from "../dependencies";
3
+
4
+ function createDeps(): Dependencies {
5
+ return {
6
+ rootDirectoryPath: "/tmp/eventvisor",
7
+ projectConfig: {
8
+ eventsDirectoryPath: "/tmp/eventvisor/events",
9
+ attributesDirectoryPath: "/tmp/eventvisor/attributes",
10
+ destinationsDirectoryPath: "/tmp/eventvisor/destinations",
11
+ statesDirectoryPath: "/tmp/eventvisor/states",
12
+ effectsDirectoryPath: "/tmp/eventvisor/effects",
13
+ testsDirectoryPath: "/tmp/eventvisor/tests",
14
+ datafilesDirectoryPath: "/tmp/eventvisor/datafiles",
15
+ systemDirectoryPath: "/tmp/eventvisor/.eventvisor",
16
+ catalogExportDirectoryPath: "/tmp/eventvisor/out",
17
+ datafileNamePattern: "eventvisor-%s.json",
18
+ tags: ["all"],
19
+ adapter: class {},
20
+ plugins: [],
21
+ parser: { extension: "yml", parse: jest.fn(), stringify: jest.fn() },
22
+ prettyDatafile: false,
23
+ stringify: true,
24
+ },
25
+ datasource: {} as Dependencies["datasource"],
26
+ options: {},
27
+ };
28
+ }
29
+
30
+ describe("getTestSchema", () => {
31
+ const schema = getTestSchema(createDeps());
32
+
33
+ it("accepts a valid attribute test", () => {
34
+ const result = schema.safeParse({
35
+ attribute: "testDefaultValue",
36
+ assertions: [
37
+ {
38
+ description: "attribute should be set",
39
+ setAttribute: {
40
+ id: "123",
41
+ country: "NL",
42
+ },
43
+ withLookups: {
44
+ "browser.screen.width": 200,
45
+ },
46
+ expectedToBeValid: true,
47
+ expectedToBeSet: true,
48
+ expectedAttribute: {
49
+ id: "123",
50
+ country: "NL",
51
+ },
52
+ },
53
+ ],
54
+ });
55
+
56
+ expect(result.success).toBe(true);
57
+ });
58
+
59
+ it("accepts a valid event test", () => {
60
+ const result = schema.safeParse({
61
+ event: "page_view",
62
+ assertions: [
63
+ {
64
+ description: "event should be valid",
65
+ withLookups: {
66
+ "browser.screen.width": 100,
67
+ },
68
+ track: {
69
+ url: "https://example.com",
70
+ },
71
+ actions: [
72
+ {
73
+ type: "setAttribute",
74
+ name: "userId",
75
+ value: "123",
76
+ },
77
+ {
78
+ type: "track",
79
+ name: "banner_click",
80
+ value: {
81
+ bannerId: "123",
82
+ },
83
+ },
84
+ ],
85
+ expectedToBeValid: true,
86
+ expectedEvent: {
87
+ url: "https://example.com",
88
+ },
89
+ expectedDestinations: ["console"],
90
+ },
91
+ ],
92
+ });
93
+
94
+ expect(result.success).toBe(true);
95
+ });
96
+
97
+ it("accepts a valid effect test", () => {
98
+ const result = schema.safeParse({
99
+ effect: "inject_cookie_banner",
100
+ assertions: [
101
+ {
102
+ description: "effect should be handled",
103
+ withLookups: {
104
+ "cookie.banner.dismissed": false,
105
+ },
106
+ actions: [
107
+ {
108
+ type: "track",
109
+ name: "page_view",
110
+ value: {
111
+ url: "https://example.com",
112
+ },
113
+ },
114
+ ],
115
+ expectedState: {
116
+ injected: true,
117
+ },
118
+ expectedToBeCalled: [
119
+ {
120
+ handler: "pixel",
121
+ times: 1,
122
+ },
123
+ ],
124
+ },
125
+ ],
126
+ });
127
+
128
+ expect(result.success).toBe(true);
129
+ });
130
+
131
+ it("accepts a valid destination test", () => {
132
+ const result = schema.safeParse({
133
+ destination: "consoleSimple",
134
+ assertions: [
135
+ {
136
+ description: "destination valid",
137
+ withLookups: {
138
+ "geo.country": "NL",
139
+ },
140
+ actions: [
141
+ {
142
+ type: "setAttribute",
143
+ name: "userId",
144
+ value: "123",
145
+ },
146
+ {
147
+ type: "track",
148
+ name: "page_view",
149
+ value: {
150
+ url: "https://example.com",
151
+ },
152
+ },
153
+ ],
154
+ expectedToBeTransported: true,
155
+ expectedBody: {
156
+ attributes: {
157
+ userId: "123",
158
+ },
159
+ },
160
+ },
161
+ ],
162
+ });
163
+
164
+ expect(result.success).toBe(true);
165
+ });
166
+
167
+ it("rejects a test without a supported discriminator key", () => {
168
+ const result = schema.safeParse({
169
+ assertions: [],
170
+ });
171
+
172
+ expect(result.success).toBe(false);
173
+ });
174
+
175
+ it("rejects extra top-level keys", () => {
176
+ const result = schema.safeParse({
177
+ event: "page_view",
178
+ assertions: [],
179
+ archived: true,
180
+ });
181
+
182
+ expect(result.success).toBe(false);
183
+ });
184
+
185
+ it("rejects unknown assertion fields", () => {
186
+ const result = schema.safeParse({
187
+ attribute: "testRequired",
188
+ assertions: [
189
+ {
190
+ description: "attribute should be set",
191
+ unsupportedField: true,
192
+ },
193
+ ],
194
+ });
195
+
196
+ expect(result.success).toBe(false);
197
+ });
198
+
199
+ it("rejects unsupported action types", () => {
200
+ const result = schema.safeParse({
201
+ event: "page_view",
202
+ assertions: [
203
+ {
204
+ actions: [
205
+ {
206
+ type: "removeAttribute",
207
+ name: "userId",
208
+ },
209
+ ],
210
+ },
211
+ ],
212
+ });
213
+
214
+ expect(result.success).toBe(false);
215
+ });
216
+
217
+ it("rejects malformed expectedToBeCalled entries", () => {
218
+ const result = schema.safeParse({
219
+ effect: "inject_cookie_banner",
220
+ assertions: [
221
+ {
222
+ expectedToBeCalled: [
223
+ {
224
+ handler: "pixel",
225
+ times: -1,
226
+ },
227
+ ],
228
+ },
229
+ ],
230
+ });
231
+
232
+ expect(result.success).toBe(false);
233
+ });
234
+
235
+ it("rejects runtime-unsupported fields", () => {
236
+ const unsupportedSpecs = [
237
+ {
238
+ event: "page_view",
239
+ assertions: [
240
+ {
241
+ withAttributes: {
242
+ userId: "123",
243
+ },
244
+ },
245
+ ],
246
+ },
247
+ {
248
+ destination: "consoleSimple",
249
+ assertions: [
250
+ {
251
+ assertAfter: 10,
252
+ },
253
+ ],
254
+ },
255
+ {
256
+ destination: "consoleSimple",
257
+ assertions: [
258
+ {
259
+ expectedBodies: [],
260
+ },
261
+ ],
262
+ },
263
+ {
264
+ event: "page_view",
265
+ assertions: [
266
+ {
267
+ expectedDestinationsByTag: {
268
+ marketing: ["console"],
269
+ },
270
+ },
271
+ ],
272
+ },
273
+ ];
274
+
275
+ for (const spec of unsupportedSpecs) {
276
+ expect(schema.safeParse(spec).success).toBe(false);
277
+ }
278
+ });
279
+ });
@@ -1,9 +1,94 @@
1
1
  import * as z from "zod";
2
2
  import { Dependencies } from "../dependencies";
3
3
 
4
- // eslint-disable-next-line
4
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
5
  export function getTestSchema(deps: Dependencies) {
6
- return z.object({
7
- archived: z.boolean().optional(),
8
- });
6
+ const withLookupsSchema = z.record(z.string(), z.any());
7
+
8
+ const actionSchema = z
9
+ .object({
10
+ type: z.enum(["track", "setAttribute"]),
11
+ name: z.string(),
12
+ value: z.any().optional(),
13
+ })
14
+ .strict();
15
+
16
+ const attributeAssertionSchema = z
17
+ .object({
18
+ description: z.string().optional(),
19
+ setAttribute: z.any().optional(),
20
+ withLookups: withLookupsSchema.optional(),
21
+ expectedToBeValid: z.boolean().optional(),
22
+ expectedToBeSet: z.boolean().optional(),
23
+ expectedAttribute: z.any().optional(),
24
+ })
25
+ .strict();
26
+
27
+ const eventAssertionSchema = z
28
+ .object({
29
+ description: z.string().optional(),
30
+ withLookups: withLookupsSchema.optional(),
31
+ track: z.any().optional(),
32
+ actions: z.array(actionSchema).optional(),
33
+ expectedToBeValid: z.boolean().optional(),
34
+ expectedEvent: z.any().optional(),
35
+ expectedDestinations: z.array(z.string()).optional(),
36
+ })
37
+ .strict();
38
+
39
+ const effectAssertionSchema = z
40
+ .object({
41
+ description: z.string().optional(),
42
+ withLookups: withLookupsSchema.optional(),
43
+ actions: z.array(actionSchema).optional(),
44
+ expectedState: z.any().optional(),
45
+ expectedToBeCalled: z
46
+ .array(
47
+ z
48
+ .object({
49
+ handler: z.string(),
50
+ times: z.number().int().min(0).optional(),
51
+ })
52
+ .strict(),
53
+ )
54
+ .optional(),
55
+ })
56
+ .strict();
57
+
58
+ const destinationAssertionSchema = z
59
+ .object({
60
+ description: z.string().optional(),
61
+ withLookups: withLookupsSchema.optional(),
62
+ actions: z.array(actionSchema).optional(),
63
+ expectedToBeTransported: z.boolean().optional(),
64
+ expectedBody: z.any().optional(),
65
+ })
66
+ .strict();
67
+
68
+ return z.union([
69
+ z
70
+ .object({
71
+ attribute: z.string(),
72
+ assertions: z.array(attributeAssertionSchema),
73
+ })
74
+ .strict(),
75
+ z
76
+ .object({
77
+ event: z.string(),
78
+ assertions: z.array(eventAssertionSchema),
79
+ })
80
+ .strict(),
81
+ z
82
+ .object({
83
+ effect: z.string(),
84
+ assertions: z.array(effectAssertionSchema),
85
+ })
86
+ .strict(),
87
+ z
88
+ .object({
89
+ destination: z.string(),
90
+ assertions: z.array(destinationAssertionSchema),
91
+ })
92
+ .strict(),
93
+ ]);
9
94
  }