make-mp-data 2.0.1 → 2.0.12

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 (44) hide show
  1. package/dungeons/adspend.js +96 -0
  2. package/dungeons/anon.js +104 -0
  3. package/dungeons/big.js +224 -0
  4. package/dungeons/business.js +327 -0
  5. package/dungeons/complex.js +396 -0
  6. package/dungeons/experiments.js +124 -0
  7. package/dungeons/foobar.js +241 -0
  8. package/dungeons/funnels.js +272 -0
  9. package/dungeons/gaming.js +315 -0
  10. package/dungeons/mirror.js +129 -0
  11. package/dungeons/sanity.js +118 -0
  12. package/dungeons/scd.js +205 -0
  13. package/dungeons/simple.js +150 -0
  14. package/dungeons/userAgent.js +190 -0
  15. package/index.js +5 -1
  16. package/package.json +10 -1
  17. package/.claude/settings.local.json +0 -21
  18. package/.gcloudignore +0 -18
  19. package/.gitattributes +0 -2
  20. package/.prettierrc +0 -0
  21. package/.vscode/launch.json +0 -80
  22. package/.vscode/settings.json +0 -69
  23. package/.vscode/tasks.json +0 -12
  24. package/dungeons/customers/.gitkeep +0 -0
  25. package/env.yaml +0 -1
  26. package/scratch.mjs +0 -62
  27. package/scripts/dana.mjs +0 -137
  28. package/scripts/deploy.sh +0 -15
  29. package/scripts/jsdoctest.js +0 -5
  30. package/scripts/new-dungeon.sh +0 -98
  31. package/scripts/new-project.mjs +0 -14
  32. package/scripts/run-index.sh +0 -2
  33. package/scripts/update-deps.sh +0 -5
  34. package/tests/benchmark/concurrency.mjs +0 -52
  35. package/tests/cli.test.js +0 -124
  36. package/tests/coverage/.gitkeep +0 -0
  37. package/tests/e2e.test.js +0 -379
  38. package/tests/int.test.js +0 -715
  39. package/tests/testCases.mjs +0 -229
  40. package/tests/testSoup.mjs +0 -28
  41. package/tests/unit.test.js +0 -910
  42. package/tmp/.gitkeep +0 -0
  43. package/tsconfig.json +0 -18
  44. package/vitest.config.js +0 -47
package/tests/int.test.js DELETED
@@ -1,715 +0,0 @@
1
- import dayjs from "dayjs";
2
- import utc from "dayjs/plugin/utc.js";
3
- import fs from 'fs';
4
- import * as u from 'ak-tools';
5
- dayjs.extend(utc);
6
- import 'dotenv/config';
7
- import path from 'path';
8
-
9
- /** @typedef {import('../types').Dungeon} Config */
10
- /** @typedef {import('../types').EventConfig} EventConfig */
11
- /** @typedef {import("../types").EventSchema} EventSchema */
12
- /** @typedef {import('../types').ValueValid} ValueValid */
13
- /** @typedef {import('../types').HookedArray} hookArray */
14
- /** @typedef {import('../types').hookArrayOptions} hookArrayOptions */
15
- /** @typedef {import('../types').Person} Person */
16
- /** @typedef {import('../types').Funnel} Funnel */
17
- /** @typedef {import('../types').UserProfile} UserProfile */
18
- /** @typedef {import('../types').SCDSchema} SCDSchema */
19
- /** @typedef {import('../types').Storage} Storage */
20
-
21
- // Import main function
22
- import main from '../index.js';
23
-
24
- // Import generators directly
25
- import { makeAdSpend } from '../lib/generators/adspend.js';
26
- import { makeEvent } from '../lib/generators/events.js';
27
- import { makeFunnel } from '../lib/generators/funnels.js';
28
- import { makeProfile } from '../lib/generators/profiles.js';
29
- import { makeSCD } from '../lib/generators/scd.js';
30
- import { makeMirror } from '../lib/generators/mirror.js';
31
-
32
- // Import orchestrators directly
33
- import { sendToMixpanel } from '../lib/orchestrators/mixpanel-sender.js';
34
- import { userLoop } from '../lib/orchestrators/user-loop.js';
35
- import { validateDungeonConfig } from '../lib/core/config-validator.js';
36
-
37
- // Import utilities directly
38
- import { createHookArray } from '../lib/core/storage.js';
39
- import { inferFunnels } from '../lib/core/config-validator.js';
40
- import { validEvent } from '../lib/utils/utils.js';
41
- import { createContext } from '../lib/core/context.js';
42
- import { validateDungeonConfig } from '../lib/core/config-validator.js';
43
-
44
- // Alias for compatibility
45
- const hookArray = createHookArray;
46
-
47
- /**
48
- * Creates a test context object for generator function testing
49
- * @param {Object} configOverrides - Config overrides for testing
50
- * @returns {Object} Test context object
51
- */
52
- function createTestContext(configOverrides = {}) {
53
- const baseConfig = {
54
- numEvents: 100,
55
- numUsers: 10,
56
- numDays: 30,
57
- hasAdSpend: false,
58
- hasLocation: false,
59
- hasAvatar: false,
60
- verbose: false,
61
- writeToDisk: false,
62
- isAnonymous: false,
63
- hasAnonIds: false,
64
- hasSessionIds: false,
65
- concurrency: 1,
66
- ...configOverrides
67
- };
68
-
69
- const validatedConfig = validateDungeonConfig(baseConfig);
70
- const context = createContext(validatedConfig);
71
-
72
- return context;
73
- }
74
-
75
-
76
- // Mock the global variables
77
- let CAMPAIGNS;
78
- let DEFAULTS;
79
- let STORAGE;
80
- let CONFIG;
81
- import { campaigns, devices, locations } from '../lib/data/defaults.js';
82
-
83
- beforeEach(async () => {
84
- // Reset global variables before each test
85
- CAMPAIGNS = [
86
- { utm_campaign: ["campaign1", "campaign2"], utm_source: ["source1"], utm_medium: ["medium1"], utm_content: ["content1"], utm_term: ["term1"] }
87
- ];
88
- DEFAULTS = {
89
- locationsUsers: () => ({ city: 'San Francisco' }),
90
- locationsEvents: () => ({ city: 'San Francisco' }),
91
- iOSDevices: () => 'iPhone',
92
- androidDevices: () => 'Android',
93
- desktopDevices: () => 'Desktop',
94
- browsers: () => 'Chrome',
95
- campaigns: () => 'campaign1'
96
- };
97
-
98
- /** @type {Storage} */
99
- STORAGE = {
100
- eventData: await hookArray([], {}),
101
- userProfilesData: await hookArray([], {}),
102
- adSpendData: await hookArray([], {}),
103
- scdTableData: [await hookArray([], {})],
104
- groupProfilesData: await hookArray([], {}),
105
- lookupTableData: await hookArray([], {}),
106
- mirrorEventData: await hookArray([], {})
107
- };
108
-
109
-
110
- /** @type {Config} */
111
- CONFIG = {
112
- numUsers: 10,
113
- numEvents: 100,
114
- numDays: 30,
115
- simulationName: 'TestSimulation',
116
- hook: (record) => record
117
- };
118
- global.CAMPAIGNS = CAMPAIGNS;
119
- global.DEFAULTS = DEFAULTS;
120
- global.STORAGE = STORAGE;
121
- global.CONFIG = CONFIG;
122
- const FIXED_NOW = dayjs('2024-02-02').unix();
123
- global.FIXED_NOW = FIXED_NOW;
124
-
125
- });
126
-
127
- beforeEach(() => {
128
-
129
- });
130
-
131
- describe.sequential('generators', () => {
132
-
133
- test('adspend: works', async () => {
134
- const campaigns = [{
135
- utm_source: ["foo"],
136
- utm_campaign: ["one"],
137
- utm_medium: ["two"],
138
- utm_content: ["three"],
139
- utm_term: ["four"]
140
- },
141
- {
142
- utm_source: ["bar"],
143
- utm_campaign: ["five"],
144
- utm_medium: ["six"],
145
- utm_content: ["seven"],
146
- utm_term: ["eight"]
147
- }];
148
- const context = createTestContext({ hasAdSpend: true });
149
- const result = await makeAdSpend(context, dayjs().subtract(30, 'day').toISOString(), campaigns);
150
- expect(result.length).toBe(2);
151
- expect(result[0]).toHaveProperty('event', '$ad_spend');
152
- expect(result[1]).toHaveProperty('event', '$ad_spend');
153
- });
154
-
155
- test('adspend: empty', async () => {
156
- const context = createTestContext({ hasAdSpend: true });
157
- const result = await makeAdSpend(context, dayjs().subtract(30, 'day').toISOString(), []);
158
- expect(result.length).toBe(0);
159
- });
160
-
161
- test('adspend: external', async () => {
162
- const campaigns = [
163
- { utm_source: ["source1"], utm_campaign: ["one"], utm_medium: ["two"], utm_content: ["three"], utm_term: ["four"] },
164
- { utm_source: ["source2"], utm_campaign: ["two"], utm_medium: ["three"], utm_content: ["four"], utm_term: ["five"] }
165
- ];
166
- const context = createTestContext({ hasAdSpend: true });
167
- const result = await makeAdSpend(context, dayjs().subtract(30, 'day').toISOString(), campaigns);
168
- expect(result.length).toBe(2);
169
- result.forEach(event => {
170
- expect(event).toHaveProperty('event', '$ad_spend');
171
- expect(event).toHaveProperty('utm_campaign');
172
- expect(event).toHaveProperty('utm_source');
173
- expect(event).toHaveProperty('cost');
174
- expect(event).toHaveProperty('clicks');
175
- expect(event).toHaveProperty('impressions');
176
- expect(event).toHaveProperty('views');
177
- });
178
- });
179
-
180
-
181
- test('makeEvent: works', async () => {
182
- /** @type {EventConfig} */
183
- const eventConfig = {
184
- event: "test_event",
185
- properties: {
186
- prop1: ["value1", "value2"],
187
- prop2: ["value3", "value4"],
188
- prop3: ["value5"]
189
- },
190
- };
191
- const context = createTestContext();
192
- const result = await makeEvent(context, "known_id", dayjs.unix(global.FIXED_NOW).subtract(30, 'd').unix(), eventConfig, ["anon_id"], ["session_id"]);
193
- expect(result).toHaveProperty('event', 'test_event');
194
- expect(result).toHaveProperty('device_id', 'anon_id');
195
- // expect(result).toHaveProperty('user_id', 'known_id'); // Known ID not always on the event
196
- expect(result).toHaveProperty('session_id', 'session_id');
197
- expect(result).toHaveProperty('source', 'dm4');
198
- expect(result).toHaveProperty('insert_id');
199
- expect(result).toHaveProperty('time');
200
- expect(result).toHaveProperty('prop1');
201
- expect(result).toHaveProperty('prop2');
202
- expect(result.prop1 === "value1" || result.prop1 === "value2").toBeTruthy();
203
- expect(result.prop2 === "value3" || result.prop2 === "value4").toBeTruthy();
204
- expect(result).toHaveProperty('prop3', 'value5');
205
- });
206
-
207
- test('makeEvent: opt params', async () => {
208
- const eventConfig = { event: "test_event", properties: {} };
209
- const context = createTestContext();
210
- const result = await makeEvent(context, "known_id", dayjs.unix(global.FIXED_NOW).subtract(30, 'd').unix(), eventConfig);
211
- expect(result).toHaveProperty('event', 'test_event');
212
- expect(result).toHaveProperty('user_id', 'known_id');
213
- expect(result).toHaveProperty('source', 'dm4');
214
- expect(result).toHaveProperty('insert_id');
215
- expect(result).toHaveProperty('time');
216
- });
217
-
218
- test('makeEvent: correct defaults', async () => {
219
- const eventConfig = {
220
- event: "test_event",
221
- properties: {
222
- prop1: ["value1", "value2"],
223
- prop2: ["value3", "value4"]
224
- },
225
- };
226
- const context = createTestContext();
227
- const result = await makeEvent(context, "known_id", dayjs.unix(global.FIXED_NOW).subtract(30, 'd').unix(), eventConfig, ["anon_id"], ["session_id"]);
228
- expect(result.prop1 === "value1" || result.prop1 === "value2").toBeTruthy();
229
- expect(result.prop2 === "value3" || result.prop2 === "value4").toBeTruthy();
230
- });
231
-
232
-
233
- test('makeFunnel: works', async () => {
234
- const funnelConfig = {
235
- sequence: ["step1", "step2"],
236
- conversionRate: 100,
237
- order: 'sequential'
238
- };
239
- /** @type {Person} */
240
- const user = { distinct_id: "user1", name: "test", created: dayjs().toISOString(), anonymousIds: [], sessionIds: [] };
241
- /** @type {UserProfile} */
242
- const profile = { created: dayjs().toISOString(), distinct_id: "user1" };
243
- /** @type {Record<string, SCDSchema[]>} */
244
- const scd = { "scd_example": [{ distinct_id: "user1", insertTime: dayjs().toISOString(), startTime: dayjs().toISOString() }] };
245
-
246
- const context = createTestContext();
247
- const [result, converted] = await makeFunnel(context, funnelConfig, user, dayjs.unix(global.FIXED_NOW).subtract(30, 'd').unix(), profile, scd);
248
- expect(result.length).toBe(2);
249
- expect(converted).toBe(true);
250
- expect(result.every(e => validEvent(e))).toBeTruthy();
251
- });
252
-
253
- test('makeFunnel: conversion rates', async () => {
254
- const funnelConfig = {
255
- sequence: ["step1", "step2", "step3"],
256
- conversionRate: 50,
257
- order: 'sequential'
258
- };
259
- const user = { distinct_id: "user1", name: "test", created: dayjs().toISOString(), anonymousIds: [], sessionIds: [] };
260
- const profile = { created: dayjs().toISOString(), distinct_id: "user1" };
261
- const scd = { "scd_example": [{ distinct_id: "user1", insertTime: dayjs().toISOString(), startTime: dayjs().toISOString() }] };
262
-
263
- const context = createTestContext();
264
- const [result, converted] = await makeFunnel(context, funnelConfig, user, dayjs.unix(global.FIXED_NOW).subtract(30, 'd').unix(), profile, scd);
265
- expect(result.length).toBeGreaterThanOrEqual(1);
266
- expect(result.length).toBeLessThanOrEqual(3);
267
- expect(result.every(e => validEvent(e))).toBeTruthy();
268
- });
269
-
270
- test('makeFunnel: ordering', async () => {
271
- const funnelConfig = {
272
- sequence: ["step1", "step2", "step3"],
273
- conversionRate: 100,
274
- order: 'random'
275
- };
276
- const user = { distinct_id: "user1", name: "test", created: dayjs().toISOString(), anonymousIds: [], sessionIds: [] };
277
- const profile = { created: dayjs().toISOString(), distinct_id: "user1" };
278
- const scd = { "scd_example": [{ distinct_id: "user1", insertTime: dayjs().toISOString(), startTime: dayjs().toISOString() }] };
279
-
280
- const context = createTestContext();
281
- const [result, converted] = await makeFunnel(context, funnelConfig, user, dayjs.unix(global.FIXED_NOW).subtract(30, 'd').unix(), profile, scd);
282
- expect(result.length).toBe(3);
283
- expect(converted).toBe(true);
284
- expect(result.every(e => validEvent(e))).toBeTruthy();
285
- });
286
-
287
-
288
- test('makeProfile: works', async () => {
289
- const context = createTestContext();
290
- const props = {
291
- name: ["John", "Jane"],
292
- age: [25, 30]
293
- };
294
- const result = await makeProfile(context, props, { foo: "bar" });
295
- expect(result).toHaveProperty('name');
296
- expect(result).toHaveProperty('age');
297
- expect(result).toHaveProperty('foo', 'bar');
298
- expect(result.name === "John" || result.name === "Jane").toBeTruthy();
299
- expect(result.age === 25 || result.age === 30).toBeTruthy();
300
- });
301
-
302
- test('makeProfile: correct defaults', async () => {
303
- const context = createTestContext();
304
- const props = {
305
- name: ["John", "Jane"],
306
- age: [25, 30]
307
- };
308
- const result = await makeProfile(context, props);
309
- expect(result).toHaveProperty('name');
310
- expect(result).toHaveProperty('age');
311
- expect(result.name === "John" || result.name === "Jane").toBeTruthy();
312
- expect(result.age === 25 || result.age === 30).toBeTruthy();
313
- });
314
-
315
-
316
- test('makeSCD: works', async () => {
317
- const context = createTestContext();
318
- const result = await makeSCD(context, ["value1", "value2"], "prop1", "distinct_id", 5, dayjs().toISOString());
319
- expect(result.length).toBeGreaterThan(0);
320
- const [first, second] = result;
321
- expect(first).toHaveProperty('prop1');
322
- expect(second).toHaveProperty('prop1');
323
- expect(first).toHaveProperty('distinct_id', 'distinct_id');
324
- expect(second).toHaveProperty('distinct_id', 'distinct_id');
325
- expect(first).toHaveProperty('startTime');
326
- expect(second).toHaveProperty('startTime');
327
- expect(first).toHaveProperty('insertTime');
328
- expect(second).toHaveProperty('insertTime');
329
- expect(first.prop1 === "value1" || first.prop1 === "value2").toBeTruthy();
330
- expect(second.prop1 === "value1" || second.prop1 === "value2").toBeTruthy();
331
- expect(result[0]).toHaveProperty('distinct_id', 'distinct_id');
332
- expect(result[0]).toHaveProperty('startTime');
333
- expect(result[0]).toHaveProperty('insertTime');
334
- });
335
-
336
- test('makeSCD: no mutations', async () => {
337
- const context = createTestContext();
338
- const result = await makeSCD(context, ["value1", "value2"], "prop1", "distinct_id", 0, dayjs().toISOString());
339
- expect(result.length).toBe(0);
340
- });
341
-
342
- test('makeSCD: large mutations', async () => {
343
- const context = createTestContext();
344
- const result = await makeSCD(context, ["value1", "value2"], "prop1", "distinct_id", 100, dayjs().subtract(100, 'd').toISOString());
345
- expect(result.length).toBeGreaterThan(0);
346
- result.forEach(entry => {
347
- expect(entry).toHaveProperty('prop1');
348
- expect(entry).toHaveProperty('distinct_id', 'distinct_id');
349
- expect(entry).toHaveProperty('startTime');
350
- expect(entry).toHaveProperty('insertTime');
351
- expect(entry.prop1 === "value1" || entry.prop1 === "value2").toBeTruthy();
352
- });
353
- });
354
-
355
- test('mirror: create', async () => {
356
- /** @type {EventSchema} */
357
- const oldEvent = {
358
- event: "old",
359
- insert_id: "test",
360
- source: "test",
361
- time: dayjs().toISOString(),
362
- user_id: "test"
363
- };
364
-
365
- /** @type {Config} */
366
- const config = {
367
- mirrorProps: {
368
- "newProp": {
369
- events: "*",
370
- strategy: "create",
371
- values: ["new"]
372
- }
373
- }
374
- };
375
- await STORAGE.eventData.hookPush(oldEvent);
376
- //ugh side fx
377
- // Create context with the test config and storage
378
- const context = createTestContext(config);
379
- context.setStorage(STORAGE);
380
- await makeMirror(context);
381
- const [newData] = STORAGE.mirrorEventData;
382
- expect(newData).toHaveProperty('newProp', "new");
383
- });
384
-
385
- test('mirror: delete', async () => {
386
- /** @type {EventSchema} */
387
- const oldEvent = {
388
- event: "old",
389
- insert_id: "test",
390
- source: "test",
391
- time: dayjs().toISOString(),
392
- user_id: "test",
393
- oldProp: "valueToDelete"
394
- };
395
-
396
- /** @type {Config} */
397
- const config = {
398
- mirrorProps: {
399
- "oldProp": {
400
- events: "*",
401
- strategy: "delete"
402
- }
403
- }
404
- };
405
- await STORAGE.eventData.hookPush(oldEvent);
406
-
407
- // Create context with the test config and storage
408
- const context = createTestContext(config);
409
- context.setStorage(STORAGE);
410
- await makeMirror(context);
411
- const [newData] = STORAGE.mirrorEventData;
412
- expect(newData).not.toHaveProperty('oldProp');
413
- });
414
-
415
- test('mirror: fill', async () => {
416
- /** @type {EventSchema} */
417
- const oldEvent = {
418
- event: "old",
419
- insert_id: "test",
420
- source: "test",
421
- time: dayjs().subtract(8, 'days').toISOString(), // Set time to 8 days ago
422
- user_id: "test",
423
- fillProp: "initialValue"
424
- };
425
-
426
- /** @type {Config} */
427
- const config = {
428
- mirrorProps: {
429
- "fillProp": {
430
- events: "*",
431
- strategy: "fill",
432
- values: ["filledValue"],
433
- daysUnfilled: 7
434
- }
435
- }
436
- };
437
- await STORAGE.eventData.hookPush(oldEvent);
438
-
439
- // Create context with the test config and storage
440
- const context = createTestContext(config);
441
- context.setStorage(STORAGE);
442
- await makeMirror(context);
443
- const [newData] = STORAGE.mirrorEventData;
444
- expect(newData).toHaveProperty('fillProp', "filledValue");
445
- });
446
-
447
- test('mirror: update', async () => {
448
- /** @type {EventSchema} */
449
- const oldEvent = {
450
- event: "old",
451
- insert_id: "test",
452
- source: "test",
453
- time: dayjs().toISOString(),
454
- user_id: "test",
455
- updateProp: "initialValue"
456
- };
457
-
458
- /** @type {Config} */
459
- const config = {
460
- mirrorProps: {
461
- "updateProp": {
462
- events: "*",
463
- strategy: "update",
464
- values: ["updatedValue"]
465
- }
466
- }
467
- };
468
- await STORAGE.eventData.hookPush(oldEvent);
469
-
470
- // Create context with the test config and storage
471
- const context = createTestContext(config);
472
- context.setStorage(STORAGE);
473
- await makeMirror(context);
474
- const [newData] = STORAGE.mirrorEventData;
475
- expect(newData).toHaveProperty('updateProp', "initialValue");
476
- });
477
-
478
- test('mirror: update nulls', async () => {
479
- /** @type {EventSchema} */
480
- const oldEvent = {
481
- event: "old",
482
- insert_id: "test",
483
- source: "test",
484
- time: dayjs().toISOString(),
485
- user_id: "test"
486
- // updateProp is not set initially
487
- };
488
-
489
- /** @type {Config} */
490
- const config = {
491
- mirrorProps: {
492
- "updateProp": {
493
- events: "*",
494
- strategy: "update",
495
- values: ["updatedValue"]
496
- }
497
- }
498
- };
499
- await STORAGE.eventData.hookPush(oldEvent);
500
-
501
- // Create context with the test config and storage
502
- const context = createTestContext(config);
503
- context.setStorage(STORAGE);
504
- await makeMirror(context);
505
- const [newData] = STORAGE.mirrorEventData;
506
- expect(newData).toHaveProperty('updateProp', "updatedValue");
507
- });
508
-
509
-
510
- test('mirror: update with no initial value', async () => {
511
- /** @type {EventSchema} */
512
- const oldEvent = {
513
- event: "old",
514
- insert_id: "test",
515
- source: "test",
516
- time: dayjs().toISOString(),
517
- user_id: "test"
518
- // updateProp is not set initially
519
- };
520
-
521
- /** @type {Config} */
522
- const config = {
523
- mirrorProps: {
524
- "updateProp": {
525
- events: "*",
526
- strategy: "update",
527
- values: ["updatedValue"]
528
- }
529
- }
530
- };
531
- await STORAGE.eventData.hookPush(oldEvent);
532
-
533
- // Create context with the test config and storage
534
- const context = createTestContext(config);
535
- context.setStorage(STORAGE);
536
- await makeMirror(context);
537
- const [newData] = STORAGE.mirrorEventData;
538
- expect(newData).toHaveProperty('updateProp', "updatedValue");
539
- });
540
-
541
-
542
-
543
- });
544
-
545
- describe.sequential('orchestrators', () => {
546
-
547
- test('sendToMixpanel: works', async () => {
548
- CONFIG.token = "test_token";
549
- const context = createTestContext(CONFIG);
550
- context.setStorage(STORAGE);
551
- const result = await sendToMixpanel(context);
552
- expect(result).toHaveProperty('events');
553
- expect(result).toHaveProperty('users');
554
- expect(result).toHaveProperty('groups');
555
- });
556
-
557
- test('sendToMixpanel: no token', async () => {
558
- CONFIG.token = null;
559
- const context = createTestContext(CONFIG);
560
- context.setStorage(STORAGE);
561
- await expect(sendToMixpanel(context)).rejects.toThrow();
562
- });
563
-
564
- test('sendToMixpanel: empty storage', async () => {
565
- CONFIG.token = "test_token";
566
- STORAGE = {
567
- eventData: await hookArray([], {}),
568
- userProfilesData: await hookArray([], {}),
569
- adSpendData: await hookArray([], {}),
570
- scdTableData: [await hookArray([], {})],
571
- groupProfilesData: await hookArray([], {}),
572
- lookupTableData: await hookArray([], {}),
573
- mirrorEventData: await hookArray([], {})
574
- };
575
- const context = createTestContext(CONFIG);
576
- context.setStorage(STORAGE);
577
- const result = await sendToMixpanel(context);
578
- expect(result.events.success).toBe(0);
579
- expect(result.users.success).toBe(0);
580
- expect(result.groups).toHaveLength(0);
581
- });
582
-
583
-
584
- test('userLoop: works (no funnels; no inference)', async () => {
585
- /** @type {Config} */
586
- const config = {
587
- numUsers: 2,
588
- numEvents: 40,
589
- numDays: 30,
590
- userProps: {},
591
- scdProps: {},
592
- funnels: [],
593
- isAnonymous: false,
594
- hasAnonIds: false,
595
- hasSessionIds: false,
596
- hasLocation: false,
597
- alsoInferFunnels: false,
598
- events: [{ event: "foo" }, { event: "bar" }, { event: "baz" }]
599
- };
600
- const context = createTestContext(config);
601
- context.setStorage(STORAGE);
602
- await userLoop(context);
603
- expect(STORAGE.userProfilesData.length).toBe(2);
604
- expect(STORAGE.eventData.length).toBeGreaterThan(15);
605
- expect(STORAGE.eventData.every(e => validEvent(e))).toBeTruthy();
606
- });
607
-
608
-
609
- test('userLoop: works (funnels)', async () => {
610
- /** @type {Config} */
611
- const config = {
612
- numUsers: 2,
613
- numEvents: 50,
614
- numDays: 30,
615
- userProps: {},
616
- scdProps: {},
617
- events: [],
618
- funnels: [{ sequence: ["step1", "step2"], conversionRate: 100, order: 'sequential' }],
619
- };
620
- const context = createTestContext(config);
621
- context.setStorage(STORAGE);
622
- await userLoop(context);
623
- expect(STORAGE.userProfilesData.length).toBe(2);
624
- expect(STORAGE.eventData.length).toBeGreaterThan(15);
625
- expect(STORAGE.eventData.every(e => validEvent(e))).toBeTruthy();
626
-
627
-
628
- });
629
-
630
- test('userLoop: mixed config', async () => {
631
- const config = {
632
- numUsers: 3,
633
- numEvents: 15,
634
- numDays: 10,
635
- userProps: { name: ["Alice", "Bob", "Charlie"] },
636
- scdProps: { prop1: ["value1", "value2"] },
637
- funnels: [],
638
- events: [{ event: "event1" }, { event: "event2" }]
639
-
640
- };
641
- const context = createTestContext(config);
642
- context.setStorage(STORAGE);
643
- await userLoop(context);
644
- expect(STORAGE.userProfilesData.length).toBe(3);
645
- expect(STORAGE.eventData.length).toBeGreaterThan(5);
646
- expect(STORAGE.scdTableData[0].length).toBeGreaterThan(5);
647
- expect(STORAGE.eventData.every(e => validEvent(e))).toBeTruthy();
648
- });
649
-
650
- test('userLoop: no events', async () => {
651
- const config = {
652
- numUsers: 2,
653
- numEvents: 0,
654
- numDays: 30,
655
- userProps: {},
656
- scdProps: {},
657
- funnels: [],
658
- isAnonymous: false,
659
- hasAnonIds: false,
660
- hasSessionIds: false,
661
- hasLocation: false,
662
- events: []
663
- };
664
- const context = createTestContext(config);
665
- context.setStorage(STORAGE);
666
- await userLoop(context);
667
- expect(STORAGE.userProfilesData.length).toBe(2);
668
- expect(STORAGE.eventData.length).toBe(0);
669
- });
670
-
671
-
672
-
673
- test('validateDungeonConfig: works', async () => {
674
- const config = {
675
- numEvents: 100,
676
- numUsers: 10,
677
- numDays: 30
678
- };
679
- const result = await validateDungeonConfig(config);
680
- expect(result).toHaveProperty('numEvents', 100);
681
- expect(result).toHaveProperty('numUsers', 10);
682
- expect(result).toHaveProperty('numDays', 30);
683
- expect(result).toHaveProperty('events');
684
- expect(result).toHaveProperty('superProps');
685
- });
686
-
687
- test('validateDungeonConfig: correct defaults', async () => {
688
- const config = {};
689
- const result = await validateDungeonConfig(config);
690
- expect(result).toHaveProperty('numEvents', 100_000);
691
- expect(result).toHaveProperty('numUsers', 1000);
692
- expect(result).toHaveProperty('numDays', 30);
693
- expect(result).toHaveProperty('events');
694
- expect(result).toHaveProperty('superProps');
695
- });
696
-
697
- test('validateDungeonConfig: merges', async () => {
698
- const config = {
699
- numEvents: 100,
700
- numUsers: 10,
701
- numDays: 30,
702
- events: [{ event: "test_event" }],
703
- superProps: { luckyNumber: [7] }
704
- };
705
- const result = await validateDungeonConfig(config);
706
- expect(result).toHaveProperty('numEvents', 100);
707
- expect(result).toHaveProperty('numUsers', 10);
708
- expect(result).toHaveProperty('numDays', 30);
709
- expect(result).toHaveProperty('events', [{ event: "test_event" }]);
710
- expect(result).toHaveProperty('superProps', { luckyNumber: [7] });
711
- });
712
-
713
-
714
-
715
- });