@mostly-good-metrics/javascript 0.5.0 → 0.6.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.
- package/dist/cjs/client.js +210 -5
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/index.js +5 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/storage.js +46 -0
- package/dist/cjs/storage.js.map +1 -1
- package/dist/cjs/types.js +1 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/client.js +210 -5
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.js +5 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/storage.js +46 -0
- package/dist/esm/storage.js.map +1 -1
- package/dist/esm/types.js +1 -0
- package/dist/esm/types.js.map +1 -1
- package/dist/types/client.d.ts +72 -5
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/index.d.ts +6 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/storage.d.ts +20 -0
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types/types.d.ts +33 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client.test.ts +346 -0
- package/src/client.ts +249 -5
- package/src/index.ts +8 -2
- package/src/storage.ts +51 -0
- package/src/types.ts +38 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -19,12 +19,15 @@
|
|
|
19
19
|
* page: '/checkout',
|
|
20
20
|
* });
|
|
21
21
|
*
|
|
22
|
-
* // Identify users
|
|
23
|
-
* MostlyGoodMetrics.identify('user_123'
|
|
22
|
+
* // Identify users with profile data
|
|
23
|
+
* MostlyGoodMetrics.identify('user_123', {
|
|
24
|
+
* email: 'user@example.com',
|
|
25
|
+
* name: 'Jane Doe',
|
|
26
|
+
* });
|
|
24
27
|
* ```
|
|
25
28
|
*/
|
|
26
29
|
export { MostlyGoodMetrics } from './client';
|
|
27
|
-
export type { MGMConfiguration, ResolvedConfiguration, EventProperties, EventPropertyValue, MGMEvent, MGMEventContext, MGMEventsPayload, Platform, SDK, DeviceType, MGMErrorType, SendResult, IEventStorage, INetworkClient, } from './types';
|
|
30
|
+
export type { MGMConfiguration, ResolvedConfiguration, EventProperties, EventPropertyValue, MGMEvent, MGMEventContext, MGMEventsPayload, Platform, SDK, DeviceType, MGMErrorType, SendResult, IEventStorage, INetworkClient, UserProfile, Experiment, ExperimentsResponse, } from './types';
|
|
28
31
|
export { MGMError } from './types';
|
|
29
32
|
export { SystemEvents, SystemProperties, DefaultConfiguration, Constraints, EVENT_NAME_REGEX, } from './types';
|
|
30
33
|
export { InMemoryEventStorage, LocalStorageEventStorage, createDefaultStorage } from './storage';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG7C,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,GAAG,EACH,UAAU,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,cAAc,EACd,WAAW,EACX,UAAU,EACV,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACX,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGjG,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAG3E,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/types/storage.d.ts
CHANGED
|
@@ -127,6 +127,26 @@ declare class PersistenceManager {
|
|
|
127
127
|
*/
|
|
128
128
|
clearSuperProperties(): void;
|
|
129
129
|
private saveSuperProperties;
|
|
130
|
+
/**
|
|
131
|
+
* Get the stored identify hash (for debouncing).
|
|
132
|
+
*/
|
|
133
|
+
getIdentifyHash(): string | null;
|
|
134
|
+
/**
|
|
135
|
+
* Set the identify hash.
|
|
136
|
+
*/
|
|
137
|
+
setIdentifyHash(hash: string): void;
|
|
138
|
+
/**
|
|
139
|
+
* Get the timestamp of the last identify event sent.
|
|
140
|
+
*/
|
|
141
|
+
getIdentifyLastSentAt(): number | null;
|
|
142
|
+
/**
|
|
143
|
+
* Set the timestamp of the last identify event sent.
|
|
144
|
+
*/
|
|
145
|
+
setIdentifyLastSentAt(timestamp: number): void;
|
|
146
|
+
/**
|
|
147
|
+
* Clear identify debounce state (used when resetting identity).
|
|
148
|
+
*/
|
|
149
|
+
clearIdentifyState(): void;
|
|
130
150
|
}
|
|
131
151
|
export declare const persistence: PersistenceManager;
|
|
132
152
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,eAAe,EAAE,aAAa,EAAY,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -305,7 +305,40 @@ export declare const SystemEvents: {
|
|
|
305
305
|
readonly APP_UPDATED: "$app_updated";
|
|
306
306
|
readonly APP_OPENED: "$app_opened";
|
|
307
307
|
readonly APP_BACKGROUNDED: "$app_backgrounded";
|
|
308
|
+
readonly IDENTIFY: "$identify";
|
|
308
309
|
};
|
|
310
|
+
/**
|
|
311
|
+
* User profile data for the identify() call.
|
|
312
|
+
*/
|
|
313
|
+
export interface UserProfile {
|
|
314
|
+
/**
|
|
315
|
+
* The user's email address.
|
|
316
|
+
*/
|
|
317
|
+
email?: string;
|
|
318
|
+
/**
|
|
319
|
+
* The user's display name.
|
|
320
|
+
*/
|
|
321
|
+
name?: string;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* An experiment configuration from the server.
|
|
325
|
+
*/
|
|
326
|
+
export interface Experiment {
|
|
327
|
+
/**
|
|
328
|
+
* The experiment identifier (e.g., "button-color").
|
|
329
|
+
*/
|
|
330
|
+
id: string;
|
|
331
|
+
/**
|
|
332
|
+
* The variants for this experiment (e.g., ["a", "b"]).
|
|
333
|
+
*/
|
|
334
|
+
variants: string[];
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Response from the experiments API endpoint.
|
|
338
|
+
*/
|
|
339
|
+
export interface ExperimentsResponse {
|
|
340
|
+
experiments: Experiment[];
|
|
341
|
+
}
|
|
309
342
|
/**
|
|
310
343
|
* System property keys (prefixed with $).
|
|
311
344
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostly-good-metrics/javascript",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "JavaScript/TypeScript SDK for MostlyGoodMetrics - a lightweight analytics library for web applications",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
package/src/client.test.ts
CHANGED
|
@@ -266,6 +266,97 @@ describe('MostlyGoodMetrics', () => {
|
|
|
266
266
|
MostlyGoodMetrics.identify('');
|
|
267
267
|
expect(MostlyGoodMetrics.shared?.userId).toBe('user_123');
|
|
268
268
|
});
|
|
269
|
+
|
|
270
|
+
it('should send $identify event with email', async () => {
|
|
271
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
272
|
+
MostlyGoodMetrics.identify('user_123', { email: 'test@example.com' });
|
|
273
|
+
|
|
274
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
275
|
+
|
|
276
|
+
const events = await storage.fetchEvents(10);
|
|
277
|
+
const identifyEvent = events.find((e) => e.name === '$identify');
|
|
278
|
+
expect(identifyEvent).toBeDefined();
|
|
279
|
+
expect(identifyEvent?.properties?.email).toBe('test@example.com');
|
|
280
|
+
expect(identifyEvent?.properties?.name).toBeUndefined();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should send $identify event with name', async () => {
|
|
284
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
285
|
+
MostlyGoodMetrics.identify('user_123', { name: 'John Doe' });
|
|
286
|
+
|
|
287
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
288
|
+
|
|
289
|
+
const events = await storage.fetchEvents(10);
|
|
290
|
+
const identifyEvent = events.find((e) => e.name === '$identify');
|
|
291
|
+
expect(identifyEvent).toBeDefined();
|
|
292
|
+
expect(identifyEvent?.properties?.name).toBe('John Doe');
|
|
293
|
+
expect(identifyEvent?.properties?.email).toBeUndefined();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('should send $identify event with both email and name', async () => {
|
|
297
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
298
|
+
MostlyGoodMetrics.identify('user_123', { email: 'test@example.com', name: 'John Doe' });
|
|
299
|
+
|
|
300
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
301
|
+
|
|
302
|
+
const events = await storage.fetchEvents(10);
|
|
303
|
+
const identifyEvent = events.find((e) => e.name === '$identify');
|
|
304
|
+
expect(identifyEvent).toBeDefined();
|
|
305
|
+
expect(identifyEvent?.properties?.email).toBe('test@example.com');
|
|
306
|
+
expect(identifyEvent?.properties?.name).toBe('John Doe');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should not send $identify event without profile data', async () => {
|
|
310
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
311
|
+
MostlyGoodMetrics.identify('user_123');
|
|
312
|
+
|
|
313
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
314
|
+
|
|
315
|
+
const events = await storage.fetchEvents(10);
|
|
316
|
+
const identifyEvent = events.find((e) => e.name === '$identify');
|
|
317
|
+
expect(identifyEvent).toBeUndefined();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should debounce $identify event with same profile data', async () => {
|
|
321
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
322
|
+
|
|
323
|
+
MostlyGoodMetrics.identify('user_123', { email: 'debounce-test@example.com' });
|
|
324
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
325
|
+
|
|
326
|
+
// Call again with same data - should not send another event
|
|
327
|
+
MostlyGoodMetrics.identify('user_123', { email: 'debounce-test@example.com' });
|
|
328
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
329
|
+
|
|
330
|
+
const events = await storage.fetchEvents(10);
|
|
331
|
+
const identifyEvents = events.filter((e) => e.name === '$identify');
|
|
332
|
+
expect(identifyEvents.length).toBe(1);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should send new $identify event when profile data changes', async () => {
|
|
336
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
337
|
+
|
|
338
|
+
MostlyGoodMetrics.identify('user_123', { email: 'change-test@example.com' });
|
|
339
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
340
|
+
|
|
341
|
+
// Call with different email - should send new event
|
|
342
|
+
MostlyGoodMetrics.identify('user_123', { email: 'changed@example.com' });
|
|
343
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
344
|
+
|
|
345
|
+
const events = await storage.fetchEvents(10);
|
|
346
|
+
const identifyEvents = events.filter((e) => e.name === '$identify');
|
|
347
|
+
expect(identifyEvents.length).toBe(2);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('should not send $identify event with empty profile', async () => {
|
|
351
|
+
MostlyGoodMetrics.resetIdentity(); // Clear any previous identify state
|
|
352
|
+
MostlyGoodMetrics.identify('user_123', {});
|
|
353
|
+
|
|
354
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
355
|
+
|
|
356
|
+
const events = await storage.fetchEvents(10);
|
|
357
|
+
const identifyEvent = events.find((e) => e.name === '$identify');
|
|
358
|
+
expect(identifyEvent).toBeUndefined();
|
|
359
|
+
});
|
|
269
360
|
});
|
|
270
361
|
|
|
271
362
|
describe('resetIdentity', () => {
|
|
@@ -702,4 +793,259 @@ describe('MostlyGoodMetrics', () => {
|
|
|
702
793
|
expect(events[0].properties?.$device_type).not.toBe('hacked');
|
|
703
794
|
});
|
|
704
795
|
});
|
|
796
|
+
|
|
797
|
+
describe('getVariant', () => {
|
|
798
|
+
let originalFetch: typeof global.fetch;
|
|
799
|
+
|
|
800
|
+
beforeEach(() => {
|
|
801
|
+
originalFetch = global.fetch;
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
afterEach(() => {
|
|
805
|
+
global.fetch = originalFetch;
|
|
806
|
+
MostlyGoodMetrics.reset();
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it('should return null when SDK not configured', () => {
|
|
810
|
+
const variant = MostlyGoodMetrics.getVariant('button-color');
|
|
811
|
+
expect(variant).toBeNull();
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it('should return null when experiment not found after experiments loaded', async () => {
|
|
815
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
816
|
+
ok: true,
|
|
817
|
+
json: () => Promise.resolve({ experiments: [] }),
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
MostlyGoodMetrics.configure({
|
|
821
|
+
apiKey: 'test-key',
|
|
822
|
+
storage,
|
|
823
|
+
networkClient,
|
|
824
|
+
trackAppLifecycleEvents: false,
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
await MostlyGoodMetrics.ready();
|
|
828
|
+
|
|
829
|
+
const variant = MostlyGoodMetrics.getVariant('nonexistent-experiment');
|
|
830
|
+
expect(variant).toBeNull();
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
it('should return null when called before experiments are loaded', async () => {
|
|
834
|
+
// Never resolve the fetch
|
|
835
|
+
global.fetch = jest.fn().mockImplementation(() => new Promise(() => {}));
|
|
836
|
+
|
|
837
|
+
MostlyGoodMetrics.configure({
|
|
838
|
+
apiKey: 'test-key',
|
|
839
|
+
storage,
|
|
840
|
+
networkClient,
|
|
841
|
+
trackAppLifecycleEvents: false,
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
// Don't wait for ready - experiments not loaded yet
|
|
845
|
+
const variant = MostlyGoodMetrics.getVariant('button-color');
|
|
846
|
+
expect(variant).toBeNull();
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
it('should return variant when experiment exists', async () => {
|
|
850
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
851
|
+
ok: true,
|
|
852
|
+
json: () =>
|
|
853
|
+
Promise.resolve({
|
|
854
|
+
experiments: [{ id: 'button-color', variants: ['a', 'b'] }],
|
|
855
|
+
}),
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
MostlyGoodMetrics.configure({
|
|
859
|
+
apiKey: 'test-key',
|
|
860
|
+
storage,
|
|
861
|
+
networkClient,
|
|
862
|
+
trackAppLifecycleEvents: false,
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
await MostlyGoodMetrics.ready();
|
|
866
|
+
|
|
867
|
+
const variant = MostlyGoodMetrics.getVariant('button-color');
|
|
868
|
+
expect(variant).not.toBeNull();
|
|
869
|
+
expect(['a', 'b']).toContain(variant);
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
it('should be deterministic - same user gets same variant', async () => {
|
|
873
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
874
|
+
ok: true,
|
|
875
|
+
json: () =>
|
|
876
|
+
Promise.resolve({
|
|
877
|
+
experiments: [{ id: 'button-color', variants: ['a', 'b', 'c'] }],
|
|
878
|
+
}),
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
MostlyGoodMetrics.configure({
|
|
882
|
+
apiKey: 'test-key',
|
|
883
|
+
storage,
|
|
884
|
+
networkClient,
|
|
885
|
+
trackAppLifecycleEvents: false,
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
await MostlyGoodMetrics.ready();
|
|
889
|
+
|
|
890
|
+
// Call multiple times - should return same variant
|
|
891
|
+
const variant1 = MostlyGoodMetrics.getVariant('button-color');
|
|
892
|
+
const variant2 = MostlyGoodMetrics.getVariant('button-color');
|
|
893
|
+
const variant3 = MostlyGoodMetrics.getVariant('button-color');
|
|
894
|
+
|
|
895
|
+
expect(variant1).toBe(variant2);
|
|
896
|
+
expect(variant2).toBe(variant3);
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
it('should store variant as super property', async () => {
|
|
900
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
901
|
+
ok: true,
|
|
902
|
+
json: () =>
|
|
903
|
+
Promise.resolve({
|
|
904
|
+
experiments: [{ id: 'button-color', variants: ['a', 'b'] }],
|
|
905
|
+
}),
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
MostlyGoodMetrics.configure({
|
|
909
|
+
apiKey: 'test-key',
|
|
910
|
+
storage,
|
|
911
|
+
networkClient,
|
|
912
|
+
trackAppLifecycleEvents: false,
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
await MostlyGoodMetrics.ready();
|
|
916
|
+
|
|
917
|
+
const variant = MostlyGoodMetrics.getVariant('button-color');
|
|
918
|
+
|
|
919
|
+
const superProps = MostlyGoodMetrics.getSuperProperties();
|
|
920
|
+
expect(superProps.experiment_button_color).toBe(variant);
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
it('should attach experiment variant to tracked events', async () => {
|
|
924
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
925
|
+
ok: true,
|
|
926
|
+
json: () =>
|
|
927
|
+
Promise.resolve({
|
|
928
|
+
experiments: [{ id: 'checkout-flow', variants: ['control', 'treatment'] }],
|
|
929
|
+
}),
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
MostlyGoodMetrics.configure({
|
|
933
|
+
apiKey: 'test-key',
|
|
934
|
+
storage,
|
|
935
|
+
networkClient,
|
|
936
|
+
trackAppLifecycleEvents: false,
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
await MostlyGoodMetrics.ready();
|
|
940
|
+
|
|
941
|
+
const variant = MostlyGoodMetrics.getVariant('checkout-flow');
|
|
942
|
+
MostlyGoodMetrics.track('purchase_completed');
|
|
943
|
+
|
|
944
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
945
|
+
|
|
946
|
+
const events = await storage.fetchEvents(1);
|
|
947
|
+
expect(events[0].properties?.experiment_checkout_flow).toBe(variant);
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
it('should handle fetch failure gracefully', async () => {
|
|
951
|
+
global.fetch = jest.fn().mockRejectedValue(new Error('Network error'));
|
|
952
|
+
|
|
953
|
+
MostlyGoodMetrics.configure({
|
|
954
|
+
apiKey: 'test-key',
|
|
955
|
+
storage,
|
|
956
|
+
networkClient,
|
|
957
|
+
trackAppLifecycleEvents: false,
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
// Should resolve even on fetch failure
|
|
961
|
+
await MostlyGoodMetrics.ready();
|
|
962
|
+
|
|
963
|
+
const variant = MostlyGoodMetrics.getVariant('button-color');
|
|
964
|
+
expect(variant).toBeNull();
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
it('should handle non-ok response gracefully', async () => {
|
|
968
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
969
|
+
ok: false,
|
|
970
|
+
status: 500,
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
MostlyGoodMetrics.configure({
|
|
974
|
+
apiKey: 'test-key',
|
|
975
|
+
storage,
|
|
976
|
+
networkClient,
|
|
977
|
+
trackAppLifecycleEvents: false,
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
await MostlyGoodMetrics.ready();
|
|
981
|
+
|
|
982
|
+
const variant = MostlyGoodMetrics.getVariant('button-color');
|
|
983
|
+
expect(variant).toBeNull();
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
it('should convert experiment name to snake_case for property', async () => {
|
|
987
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
988
|
+
ok: true,
|
|
989
|
+
json: () =>
|
|
990
|
+
Promise.resolve({
|
|
991
|
+
experiments: [{ id: 'newOnboardingFlow', variants: ['a', 'b'] }],
|
|
992
|
+
}),
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
MostlyGoodMetrics.configure({
|
|
996
|
+
apiKey: 'test-key',
|
|
997
|
+
storage,
|
|
998
|
+
networkClient,
|
|
999
|
+
trackAppLifecycleEvents: false,
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
await MostlyGoodMetrics.ready();
|
|
1003
|
+
|
|
1004
|
+
MostlyGoodMetrics.getVariant('newOnboardingFlow');
|
|
1005
|
+
|
|
1006
|
+
const superProps = MostlyGoodMetrics.getSuperProperties();
|
|
1007
|
+
expect(superProps.experiment_new_onboarding_flow).toBeDefined();
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
it('should return null for empty experimentName', async () => {
|
|
1011
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
1012
|
+
ok: true,
|
|
1013
|
+
json: () => Promise.resolve({ experiments: [] }),
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
MostlyGoodMetrics.configure({
|
|
1017
|
+
apiKey: 'test-key',
|
|
1018
|
+
storage,
|
|
1019
|
+
networkClient,
|
|
1020
|
+
trackAppLifecycleEvents: false,
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
await MostlyGoodMetrics.ready();
|
|
1024
|
+
|
|
1025
|
+
const variant = MostlyGoodMetrics.getVariant('');
|
|
1026
|
+
expect(variant).toBeNull();
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
it('should return null for experiment with no variants', async () => {
|
|
1030
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
1031
|
+
ok: true,
|
|
1032
|
+
json: () =>
|
|
1033
|
+
Promise.resolve({
|
|
1034
|
+
experiments: [{ id: 'empty-experiment', variants: [] }],
|
|
1035
|
+
}),
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
MostlyGoodMetrics.configure({
|
|
1039
|
+
apiKey: 'test-key',
|
|
1040
|
+
storage,
|
|
1041
|
+
networkClient,
|
|
1042
|
+
trackAppLifecycleEvents: false,
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
await MostlyGoodMetrics.ready();
|
|
1046
|
+
|
|
1047
|
+
const variant = MostlyGoodMetrics.getVariant('empty-experiment');
|
|
1048
|
+
expect(variant).toBeNull();
|
|
1049
|
+
});
|
|
1050
|
+
});
|
|
705
1051
|
});
|