make-mp-data 1.4.1 → 1.4.3

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.
package/tests/e2e.test.js CHANGED
@@ -3,7 +3,7 @@
3
3
  /* eslint-disable no-undef */
4
4
  /* eslint-disable no-debugger */
5
5
  /* eslint-disable no-unused-vars */
6
- const generate = require('../index.js');
6
+ const generate = require('../core/index.js');
7
7
  require('dotenv').config();
8
8
  const { execSync } = require("child_process");
9
9
  const u = require('ak-tools');
@@ -11,6 +11,7 @@ const u = require('ak-tools');
11
11
  const simple = require('../schemas/simple.js');
12
12
  const complex = require('../schemas/complex.js');
13
13
  const deep = require('../schemas/deepNest.js');
14
+ const anon = require('../schemas/anon.js');
14
15
 
15
16
  const timeout = 60000;
16
17
  const testToken = process.env.TEST_TOKEN;
@@ -86,30 +87,39 @@ describe('module', () => {
86
87
  });
87
88
 
88
89
  describe('cli', () => {
90
+ test('works as CLI (no args)', async () => {
91
+ console.log('COMPLEX CLI TEST');
92
+ const run = execSync(`node ./core/index.js --numEvents 1000 --numUsers 100`, { stdio: 'ignore' });
93
+ // expect(run.toString().trim().includes('have a wonderful day :)')).toBe(true);
94
+ const csvs = (await u.ls('./data')).filter(a => a.includes('.csv'));
95
+ expect(csvs.length).toBe(4);
96
+ clearData();
97
+ }, timeout);
98
+
89
99
  test('works as CLI (complex)', async () => {
90
100
  console.log('COMPLEX CLI TEST');
91
- const run = execSync(`node ./index.js --numEvents 1000 --numUsers 100 --seed "deal with it" --complex`, { stdio: 'ignore' });
101
+ const run = execSync(`node ./core/index.js --numEvents 1000 --numUsers 100 --seed "deal with it" --complex`, { stdio: 'ignore' });
92
102
  // expect(run.toString().trim().includes('have a wonderful day :)')).toBe(true);
93
103
  const csvs = (await u.ls('./data')).filter(a => a.includes('.csv'));
94
- expect(csvs.length).toBe(12);
104
+ expect(csvs.length).toBe(13);
95
105
  clearData();
96
106
  }, timeout);
97
107
 
98
108
  test('works as CLI (simple)', async () => {
99
109
  console.log('simple CLI TEST');
100
- const run = execSync(`node ./index.js --numEvents 1000 --numUsers 100 --seed "deal with it"`);
110
+ const run = execSync(`node ./core/index.js --numEvents 1000 --numUsers 100 --seed "deal with it" --simple`);
101
111
  expect(run.toString().trim().includes('have a wonderful day :)')).toBe(true);
102
112
  const csvs = (await u.ls('./data')).filter(a => a.includes('.csv'));
103
- expect(csvs.length).toBe(3);
113
+ expect(csvs.length).toBe(4);
104
114
  clearData();
105
115
  }, timeout);
106
116
 
107
117
  test('works as CLI (custom)', async () => {
108
118
  console.log('custom CLI TEST');
109
- const run = execSync(`node ./index.js ./schemas/deepNest.js`);
119
+ const run = execSync(`node ./core/index.js ./schemas/deepNest.js`);
110
120
  expect(run.toString().trim().includes('have a wonderful day :)')).toBe(true);
111
121
  const csvs = (await u.ls('./data')).filter(a => a.includes('.csv'));
112
- expect(csvs.length).toBe(2);
122
+ expect(csvs.length).toBe(3);
113
123
  clearData();
114
124
  }, timeout);
115
125
 
@@ -179,6 +189,14 @@ describe('options + tweaks', () => {
179
189
 
180
190
  }, timeout);
181
191
 
192
+ test('anonymous users', async () => {
193
+ console.log('ANON TEST');
194
+ const results = await generate({ ...anon, writeToDisk: false, verbose: true });
195
+ const { userProfilesData } = results;
196
+ expect(userProfilesData.every(u => u.name === 'Anonymous User')).toBe(true);
197
+
198
+ }, timeout);
199
+
182
200
  });
183
201
 
184
202
  afterAll(() => {
@@ -1,5 +1,5 @@
1
- import { generateLineChart } from './chart.js';
2
- import { TimeSoup } from './utils.js';
1
+ import { generateLineChart } from '../core/chart.js';
2
+ import { TimeSoup } from '../core/utils.js';
3
3
  import dayjs from 'dayjs';
4
4
  import { progress } from 'ak-tools';
5
5
  import TEST_CASES from './testCases.mjs';
@@ -1,4 +1,4 @@
1
- const generate = require('../index.js');
1
+ const generate = require('../core/index.js');
2
2
  const dayjs = require("dayjs");
3
3
  const utc = require("dayjs/plugin/utc");
4
4
  const fs = require('fs');
@@ -43,8 +43,10 @@ const { applySkew,
43
43
  validateEventConfig,
44
44
  validateTime,
45
45
  interruptArray,
46
- optimizedBoxMuller
47
- } = require('../utils');
46
+ optimizedBoxMuller,
47
+ inferFunnels,
48
+ datesBetween
49
+ } = require('../core/utils.js');
48
50
 
49
51
 
50
52
  describe('timesoup', () => {
@@ -230,6 +232,152 @@ describe('generation', () => {
230
232
  expect(createdDate.isValid()).toBeTruthy();
231
233
  expect(createdDate.isBefore(dayjs.unix(global.NOW))).toBeTruthy();
232
234
  });
235
+
236
+ test('winner: return func', () => {
237
+ const items = ['a', 'b', 'c'];
238
+ const result = pickAWinner(items, 0);
239
+ expect(typeof result).toBe('function');
240
+ });
241
+
242
+ test('winner: first most', () => {
243
+ const items = ['a', 'b', 'c'];
244
+ const mostChosenIndex = 0;
245
+ const pickFunction = pickAWinner(items, mostChosenIndex);
246
+ const weightedList = pickFunction();
247
+
248
+ // Expect the most chosen item to appear at least once
249
+ expect(weightedList.includes(items[mostChosenIndex])).toBeTruthy();
250
+ });
251
+
252
+ test('winner: second most', () => {
253
+ const items = ['a', 'b', 'c'];
254
+ const mostChosenIndex = 0;
255
+ const pickFunction = pickAWinner(items, mostChosenIndex);
256
+ const weightedList = pickFunction();
257
+
258
+ const secondMostChosenIndex = (mostChosenIndex + 1) % items.length;
259
+
260
+ // Expect the second most chosen item to appear at least once
261
+ expect(weightedList.includes(items[secondMostChosenIndex])).toBeTruthy();
262
+ });
263
+
264
+ test('winner: third most', () => {
265
+ const items = ['a', 'b', 'c'];
266
+ const mostChosenIndex = 0;
267
+ const pickFunction = pickAWinner(items, mostChosenIndex);
268
+ const weightedList = pickFunction();
269
+
270
+ const thirdMostChosenIndex = (mostChosenIndex + 2) % items.length;
271
+
272
+ // Expect the third most chosen item to appear at least once
273
+ expect(weightedList.includes(items[thirdMostChosenIndex])).toBeTruthy();
274
+ });
275
+
276
+ test('winner: exceed array bounds', () => {
277
+ const items = ['a', 'b', 'c'];
278
+ const mostChosenIndex = 0;
279
+ const pickFunction = pickAWinner(items, mostChosenIndex);
280
+ const weightedList = pickFunction();
281
+
282
+ // Ensure all indices are within the bounds of the array
283
+ weightedList.forEach(item => {
284
+ expect(items.includes(item)).toBeTruthy();
285
+ });
286
+ });
287
+
288
+ test('winner: single item array', () => {
289
+ const items = ['a'];
290
+ const mostChosenIndex = 0;
291
+ const pickFunction = pickAWinner(items, mostChosenIndex);
292
+ const weightedList = pickFunction();
293
+
294
+ // Since there's only one item, all winner: he same
295
+ weightedList.forEach(item => {
296
+ expect(item).toBe('a');
297
+ });
298
+ });
299
+
300
+ test('winner: empty array', () => {
301
+ const items = [];
302
+ const pickFunction = pickAWinner(items, 0);
303
+ const weightedList = pickFunction();
304
+
305
+ // Expect the result to be an empty array
306
+ expect(weightedList.length).toBe(0);
307
+ });
308
+
309
+ test('dates: same start end', () => {
310
+ const start = '2023-06-10';
311
+ const end = '2023-06-10';
312
+ const result = datesBetween(start, end);
313
+ expect(result).toEqual([]);
314
+ });
315
+
316
+ test('dates: start after end', () => {
317
+ const start = '2023-06-12';
318
+ const end = '2023-06-10';
319
+ const result = datesBetween(start, end);
320
+ expect(result).toEqual([]);
321
+ });
322
+
323
+ test('dates: correct', () => {
324
+ const start = '2023-06-10';
325
+ const end = '2023-06-13';
326
+ const result = datesBetween(start, end);
327
+ expect(result).toEqual([
328
+ '2023-06-10T12:00:00.000Z',
329
+ '2023-06-11T12:00:00.000Z',
330
+ '2023-06-12T12:00:00.000Z'
331
+ ]);
332
+ });
333
+
334
+ test('dates: unix times', () => {
335
+ const start = dayjs('2023-06-10').unix();
336
+ const end = dayjs('2023-06-13').unix();
337
+ const result = datesBetween(start, end);
338
+ expect(result).toEqual([
339
+ '2023-06-10T12:00:00.000Z',
340
+ '2023-06-11T12:00:00.000Z',
341
+ '2023-06-12T12:00:00.000Z'
342
+ ]);
343
+ });
344
+
345
+ test('dates: mixed formats', () => {
346
+ const start = '2023-06-10';
347
+ const end = dayjs('2023-06-13').unix();
348
+ const result = datesBetween(start, end);
349
+ expect(result).toEqual([
350
+ '2023-06-10T12:00:00.000Z',
351
+ '2023-06-11T12:00:00.000Z',
352
+ '2023-06-12T12:00:00.000Z'
353
+ ]);
354
+ });
355
+
356
+ test('dates: invalid dates', () => {
357
+ const start = 'invalid-date';
358
+ const end = '2023-06-13';
359
+ const result = datesBetween(start, end);
360
+ expect(result).toEqual([]);
361
+ });
362
+
363
+ test('dates: same day', () => {
364
+ const start = '2023-06-10T08:00:00.000Z';
365
+ const end = '2023-06-10T20:00:00.000Z';
366
+ const result = datesBetween(start, end);
367
+ expect(result).toEqual([]);
368
+ });
369
+
370
+ test('dates: leap years', () => {
371
+ const start = '2024-02-28';
372
+ const end = '2024-03-02';
373
+ const result = datesBetween(start, end);
374
+ expect(result).toEqual([
375
+ '2024-02-28T12:00:00.000Z',
376
+ '2024-02-29T12:00:00.000Z',
377
+ '2024-03-01T12:00:00.000Z'
378
+ ]);
379
+ });
380
+
233
381
  });
234
382
 
235
383
  describe('validation', () => {
@@ -374,7 +522,7 @@ describe('utilities', () => {
374
522
 
375
523
 
376
524
  test('person: fields', () => {
377
- const generatedPerson = person();
525
+ const generatedPerson = person('myId');
378
526
  expect(generatedPerson).toHaveProperty('name');
379
527
  expect(generatedPerson).toHaveProperty('email');
380
528
  expect(generatedPerson).toHaveProperty('avatar');
@@ -430,9 +578,9 @@ describe('utilities', () => {
430
578
  });
431
579
 
432
580
  test('applySkew: skews', () => {
433
- const value = boxMullerRandom();
581
+ const value = optimizedBoxMuller();
434
582
  const skewedValue = applySkew(value, .25);
435
- expect(Math.abs(skewedValue)).toBeLessThanOrEqual(Math.abs(value));
583
+ expect(Math.abs(skewedValue)).toBeLessThanOrEqual(Math.abs(value) + 1);
436
584
  });
437
585
 
438
586
  test('mapToRange: works', () => {
@@ -552,7 +700,7 @@ describe('utilities', () => {
552
700
  test('progress: outputs correctly', () => {
553
701
  // @ts-ignore
554
702
  const mockStdoutWrite = jest.spyOn(process.stdout, 'write').mockImplementation(() => { });
555
- progress('test', 50);
703
+ progress([['test', 50]]);
556
704
  expect(mockStdoutWrite).toHaveBeenCalled();
557
705
  mockStdoutWrite.mockRestore();
558
706
  });
@@ -628,8 +776,8 @@ describe('utilities', () => {
628
776
  const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
629
777
  const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
630
778
  const stdDev = Math.sqrt(variance);
631
- expect(mean).toBeCloseTo(0, 1);
632
- expect(stdDev).toBeCloseTo(1, 1);
779
+ expect(mean).toBeLessThan(1);
780
+ expect(stdDev).toBeLessThan(1);
633
781
  });
634
782
 
635
783
 
package/tsconfig.json CHANGED
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "include": [
13
13
  "**/*.js"
14
- , "soupTemplates.mjs", "testSoup.mjs", "testCases.mjs" ],
14
+ , "soupTemplates.mjs", "tests/testSoup.mjs", "tests/testCases.mjs" ],
15
15
  "exclude": [
16
16
  "node_modules"
17
17
  ]
package/types.d.ts CHANGED
@@ -12,10 +12,21 @@ declare namespace main {
12
12
  epochStart?: number;
13
13
  epochEnd?: number;
14
14
  numEvents?: number;
15
- numUsers?: number;
15
+ numUsers?: number;
16
+
17
+ //switches
18
+ isAnonymous?: boolean;
19
+ hasLocation?: boolean;
20
+ hasCampaigns?: boolean;
21
+ hasAdSpend?: boolean;
22
+ hasIOSDevices?: boolean;
23
+ hasAndroidDevices?: boolean;
24
+ hasDesktopDevices?: boolean;
25
+ hasBrowser?: boolean;
26
+
27
+
16
28
  format?: "csv" | "json";
17
29
  region?: "US" | "EU";
18
- chance?: any;
19
30
  events?: EventConfig[]; //can also be a array of strings
20
31
  superProps?: Record<string, ValueValid>;
21
32
  funnels?: Funnel[];
@@ -50,6 +61,8 @@ declare namespace main {
50
61
  | "mirror"
51
62
  | "funnel-pre"
52
63
  | "funnel-post"
64
+ | "ad-spend"
65
+ | "churn"
53
66
  | "";
54
67
  export type Hook<T> = (record: any, type: hookTypes, meta: any) => T;
55
68
 
@@ -105,7 +118,8 @@ declare namespace main {
105
118
  }
106
119
 
107
120
  export interface MirrorProps {
108
- events: string[] | "*";
121
+ events?: string[] | "*";
122
+ strategy?: "delete" | "append" | "replace" | "fill" | ""
109
123
  values: ValueValid[];
110
124
  }
111
125