@amplytools/react-native-amply-sdk 0.15.0 → 0.15.1
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/campaignTouch.js +44 -0
- package/dist/cjs/campaignTouch.js.map +1 -0
- package/dist/cjs/hooks/useAmplySystemEvents.js +60 -0
- package/dist/cjs/hooks/useAmplySystemEvents.js.map +1 -0
- package/dist/cjs/index.js +723 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/nativeModule.js +55 -0
- package/dist/cjs/nativeModule.js.map +1 -0
- package/dist/cjs/nativeSpecs/NativeAmplyModule.js +5 -0
- package/dist/cjs/nativeSpecs/NativeAmplyModule.js.map +1 -0
- package/dist/cjs/systemEventUtils.js +47 -0
- package/dist/cjs/systemEventUtils.js.map +1 -0
- package/dist/cjs/systemEvents.js +27 -0
- package/dist/cjs/systemEvents.js.map +1 -0
- package/docs/ARCHITECTURE.md +26 -19
- package/package.json +12 -6
- package/scripts/check-package.js +159 -0
- package/dist/index.js +0 -272
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -234
- package/dist/index.mjs.map +0 -1
- package/dist/plugin/index.d.ts +0 -6
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/index.js +0 -186
- package/dist/plugin/index.js.map +0 -1
- package/dist/plugin/index.mjs +0 -169
- package/dist/plugin/index.mjs.map +0 -1
- package/dist/plugin/withAmply.d.ts +0 -12
- package/dist/plugin/withAmply.d.ts.map +0 -1
- package/dist/src/__tests__/appLanguage.test.d.ts +0 -2
- package/dist/src/__tests__/appLanguage.test.d.ts.map +0 -1
- package/dist/src/__tests__/appLanguage.test.js +0 -211
- package/dist/src/__tests__/campaignResolved.test.d.ts +0 -2
- package/dist/src/__tests__/campaignResolved.test.d.ts.map +0 -1
- package/dist/src/__tests__/campaignResolved.test.js +0 -208
- package/dist/src/__tests__/gateRegistrationLifecycle.test.d.ts +0 -2
- package/dist/src/__tests__/gateRegistrationLifecycle.test.d.ts.map +0 -1
- package/dist/src/__tests__/gateRegistrationLifecycle.test.js +0 -215
- package/dist/src/__tests__/handleUrl.test.d.ts +0 -2
- package/dist/src/__tests__/handleUrl.test.d.ts.map +0 -1
- package/dist/src/__tests__/handleUrl.test.js +0 -114
- package/dist/src/__tests__/index.test.d.ts +0 -2
- package/dist/src/__tests__/index.test.d.ts.map +0 -1
- package/dist/src/__tests__/index.test.js +0 -204
- package/dist/src/__tests__/lastCampaignTouch.test.d.ts +0 -2
- package/dist/src/__tests__/lastCampaignTouch.test.d.ts.map +0 -1
- package/dist/src/__tests__/lastCampaignTouch.test.js +0 -119
- package/dist/src/__tests__/systemEventUtils.test.d.ts +0 -2
- package/dist/src/__tests__/systemEventUtils.test.d.ts.map +0 -1
- package/dist/src/__tests__/systemEventUtils.test.js +0 -72
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/plugin/tsconfig.tsbuildinfo +0 -1
- package/src/__tests__/appLanguage.test.ts +0 -298
- package/src/__tests__/campaignResolved.test.ts +0 -294
- package/src/__tests__/gateRegistrationLifecycle.test.ts +0 -281
- package/src/__tests__/handleUrl.test.ts +0 -155
- package/src/__tests__/index.test.ts +0 -258
- package/src/__tests__/lastCampaignTouch.test.ts +0 -151
- package/src/__tests__/systemEventUtils.test.ts +0 -97
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import * as Amply from '../index';
|
|
2
|
-
import { __setNativeModule } from '../nativeModule';
|
|
3
|
-
const mockNativeModule = {
|
|
4
|
-
initialize: jest.fn(),
|
|
5
|
-
isInitialized: jest.fn(() => true),
|
|
6
|
-
track: jest.fn(),
|
|
7
|
-
getRecentEvents: jest.fn(),
|
|
8
|
-
getDataSetSnapshot: jest.fn(),
|
|
9
|
-
registerDeepLinkListener: jest.fn(),
|
|
10
|
-
addListener: jest.fn(),
|
|
11
|
-
removeListeners: jest.fn(),
|
|
12
|
-
onSystemEvent: jest.fn(),
|
|
13
|
-
onDeepLink: jest.fn(),
|
|
14
|
-
setCustomProperties: jest.fn(),
|
|
15
|
-
getCustomProperty: jest.fn(),
|
|
16
|
-
removeCustomProperty: jest.fn(),
|
|
17
|
-
clearCustomProperties: jest.fn(),
|
|
18
|
-
};
|
|
19
|
-
describe('Amply JS API', () => {
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
jest.clearAllMocks();
|
|
22
|
-
__setNativeModule(null);
|
|
23
|
-
});
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
__setNativeModule(mockNativeModule);
|
|
26
|
-
});
|
|
27
|
-
it('initializes the native module', async () => {
|
|
28
|
-
await Amply.initialize({ appId: 'id', apiKeyPublic: 'public', apiKeySecret: 'secret' });
|
|
29
|
-
expect(mockNativeModule.initialize).toHaveBeenCalledWith(expect.objectContaining({ appId: 'id', apiKeyPublic: 'public' }));
|
|
30
|
-
});
|
|
31
|
-
// A missing key used to reach the native SDK, whose config builder threw an exception that
|
|
32
|
-
// crossed into Objective-C uncaught and aborted the host app — no JS try/catch could stop it.
|
|
33
|
-
// Bad keys must cost the app its Amply, never its process.
|
|
34
|
-
describe.each([
|
|
35
|
-
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public' }],
|
|
36
|
-
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public', apiKeySecret: '' }],
|
|
37
|
-
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public', apiKeySecret: ' ' }],
|
|
38
|
-
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public', apiKeySecret: null }],
|
|
39
|
-
['apiKeyPublic', { appId: 'id', apiKeyPublic: '', apiKeySecret: 'secret' }],
|
|
40
|
-
['appId', { appId: '', apiKeyPublic: 'public', apiKeySecret: 'secret' }],
|
|
41
|
-
])('when %s is missing (%j)', (field, config) => {
|
|
42
|
-
it('rejects with AMP_INVALID_CONFIG, names the field and never calls the native module', async () => {
|
|
43
|
-
const error = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
44
|
-
await expect(Amply.initialize(config)).rejects.toMatchObject({
|
|
45
|
-
code: 'AMP_INVALID_CONFIG',
|
|
46
|
-
message: expect.stringContaining(field),
|
|
47
|
-
});
|
|
48
|
-
expect(mockNativeModule.initialize).not.toHaveBeenCalled();
|
|
49
|
-
expect(error).toHaveBeenCalledWith(expect.stringContaining(field));
|
|
50
|
-
error.mockRestore();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
it('passes the base-URL overrides through to the native layer', async () => {
|
|
54
|
-
await Amply.initialize({
|
|
55
|
-
appId: 'id',
|
|
56
|
-
apiKeyPublic: 'public',
|
|
57
|
-
apiKeySecret: 'secret',
|
|
58
|
-
configBaseUrl: 'https://config-staging.example.com',
|
|
59
|
-
backendBaseUrl: 'https://api-staging.example.com',
|
|
60
|
-
});
|
|
61
|
-
expect(mockNativeModule.initialize).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
|
-
configBaseUrl: 'https://config-staging.example.com',
|
|
63
|
-
backendBaseUrl: 'https://api-staging.example.com',
|
|
64
|
-
}));
|
|
65
|
-
});
|
|
66
|
-
// `endpoint` is the older single-URL spelling. It stays accepted so existing
|
|
67
|
-
// callers keep working, but it only ever meant the backend host — the campaign
|
|
68
|
-
// manifest is served from a different one.
|
|
69
|
-
it('still accepts the legacy endpoint spelling', async () => {
|
|
70
|
-
await Amply.initialize({
|
|
71
|
-
appId: 'id',
|
|
72
|
-
apiKeyPublic: 'public',
|
|
73
|
-
apiKeySecret: 'secret',
|
|
74
|
-
endpoint: 'https://api-staging.example.com',
|
|
75
|
-
});
|
|
76
|
-
expect(mockNativeModule.initialize).toHaveBeenCalledWith(expect.objectContaining({ endpoint: 'https://api-staging.example.com' }));
|
|
77
|
-
});
|
|
78
|
-
it('tracks events through the native layer', async () => {
|
|
79
|
-
await Amply.track({ name: 'Test Event', properties: { foo: 'bar' } });
|
|
80
|
-
expect(mockNativeModule.track).toHaveBeenCalledWith({
|
|
81
|
-
name: 'Test Event',
|
|
82
|
-
properties: { foo: 'bar' },
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
it('reads recent events', async () => {
|
|
86
|
-
const events = [{ name: 'e1' }];
|
|
87
|
-
mockNativeModule.getRecentEvents.mockResolvedValueOnce(events);
|
|
88
|
-
const result = await Amply.getRecentEvents(3);
|
|
89
|
-
expect(mockNativeModule.getRecentEvents).toHaveBeenCalledWith(3);
|
|
90
|
-
expect(result).toBe(events);
|
|
91
|
-
});
|
|
92
|
-
it('requests dataset snapshots', async () => {
|
|
93
|
-
const snapshot = { foo: 'bar' };
|
|
94
|
-
mockNativeModule.getDataSetSnapshot.mockResolvedValueOnce(snapshot);
|
|
95
|
-
const type = { kind: '@device' };
|
|
96
|
-
const result = await Amply.getDataSetSnapshot(type);
|
|
97
|
-
expect(mockNativeModule.getDataSetSnapshot).toHaveBeenCalledWith(type);
|
|
98
|
-
expect(result).toBe(snapshot);
|
|
99
|
-
});
|
|
100
|
-
it.each([
|
|
101
|
-
['singleton @device', { kind: '@device' }],
|
|
102
|
-
['singleton @user', { kind: '@user' }],
|
|
103
|
-
['singleton @custom', { kind: '@custom' }],
|
|
104
|
-
['singleton @session', { kind: '@session' }],
|
|
105
|
-
[
|
|
106
|
-
'@triggeredEvent with global strategy',
|
|
107
|
-
{
|
|
108
|
-
kind: '@triggeredEvent',
|
|
109
|
-
data: {
|
|
110
|
-
countStrategy: 'global',
|
|
111
|
-
params: [{ name: 'level', value: 5 }],
|
|
112
|
-
eventName: 'LevelComplete',
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
[
|
|
117
|
-
'@triggeredEvent with session strategy and no eventName',
|
|
118
|
-
{
|
|
119
|
-
kind: '@triggeredEvent',
|
|
120
|
-
data: {
|
|
121
|
-
countStrategy: 'session',
|
|
122
|
-
params: [],
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
],
|
|
126
|
-
[
|
|
127
|
-
'@events with mixed event types',
|
|
128
|
-
{
|
|
129
|
-
kind: '@events',
|
|
130
|
-
data: [
|
|
131
|
-
{ name: 'Purchase', type: 'custom', params: [{ name: 'sku', value: 'ABC' }] },
|
|
132
|
-
{ name: 'SessionStarted', type: 'system', params: [] },
|
|
133
|
-
],
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
])('passes %s to the native bridge unchanged', async (_label, type) => {
|
|
137
|
-
mockNativeModule.getDataSetSnapshot.mockResolvedValueOnce({});
|
|
138
|
-
await Amply.getDataSetSnapshot(type);
|
|
139
|
-
expect(mockNativeModule.getDataSetSnapshot).toHaveBeenCalledWith(type);
|
|
140
|
-
});
|
|
141
|
-
it('subscribes to system events through the TurboModule emitter', async () => {
|
|
142
|
-
const remove = jest.fn();
|
|
143
|
-
mockNativeModule.onSystemEvent.mockReturnValueOnce({ remove });
|
|
144
|
-
const listener = jest.fn();
|
|
145
|
-
const unsubscribe = await Amply.addSystemEventListener(listener);
|
|
146
|
-
expect(mockNativeModule.onSystemEvent).toHaveBeenCalledTimes(1);
|
|
147
|
-
// The native listener is a wrapper that filters DebugLog events
|
|
148
|
-
const nativeListener = mockNativeModule.onSystemEvent.mock.calls[0][0];
|
|
149
|
-
// DebugLog events should be filtered out
|
|
150
|
-
nativeListener({ name: 'DebugLog', type: 'log', timestamp: 1, properties: {} });
|
|
151
|
-
expect(listener).not.toHaveBeenCalled();
|
|
152
|
-
// Other events should pass through
|
|
153
|
-
const systemEvent = { name: 'SessionStart', type: 'system', timestamp: 2, properties: {} };
|
|
154
|
-
nativeListener(systemEvent);
|
|
155
|
-
expect(listener).toHaveBeenCalledWith(systemEvent);
|
|
156
|
-
unsubscribe();
|
|
157
|
-
expect(remove).toHaveBeenCalledTimes(1);
|
|
158
|
-
});
|
|
159
|
-
it('sets a single custom property via setCustomProperties', () => {
|
|
160
|
-
Amply.setCustomProperty('plan', 'premium');
|
|
161
|
-
expect(mockNativeModule.setCustomProperties).toHaveBeenCalledWith({
|
|
162
|
-
plan: 'premium',
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
it('sets multiple custom properties at once', () => {
|
|
166
|
-
Amply.setCustomProperties({ plan: 'premium', age: 25, active: true });
|
|
167
|
-
expect(mockNativeModule.setCustomProperties).toHaveBeenCalledWith({
|
|
168
|
-
plan: 'premium',
|
|
169
|
-
age: 25,
|
|
170
|
-
active: true,
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
it('gets a custom property value', async () => {
|
|
174
|
-
mockNativeModule.getCustomProperty.mockResolvedValueOnce({ value: 'premium' });
|
|
175
|
-
const result = await Amply.getCustomProperty('plan');
|
|
176
|
-
expect(mockNativeModule.getCustomProperty).toHaveBeenCalledWith('plan');
|
|
177
|
-
expect(result).toBe('premium');
|
|
178
|
-
});
|
|
179
|
-
it('returns null for a missing custom property', async () => {
|
|
180
|
-
mockNativeModule.getCustomProperty.mockResolvedValueOnce({});
|
|
181
|
-
const result = await Amply.getCustomProperty('nonexistent');
|
|
182
|
-
expect(result).toBeNull();
|
|
183
|
-
});
|
|
184
|
-
it('removes a custom property', () => {
|
|
185
|
-
Amply.removeCustomProperty('plan');
|
|
186
|
-
expect(mockNativeModule.removeCustomProperty).toHaveBeenCalledWith('plan');
|
|
187
|
-
});
|
|
188
|
-
it('clears all custom properties', () => {
|
|
189
|
-
Amply.clearCustomProperties();
|
|
190
|
-
expect(mockNativeModule.clearCustomProperties).toHaveBeenCalled();
|
|
191
|
-
});
|
|
192
|
-
it('registers deep links once and subscribes via the TurboModule emitter', async () => {
|
|
193
|
-
const remove = jest.fn();
|
|
194
|
-
mockNativeModule.onDeepLink.mockReturnValue({ remove });
|
|
195
|
-
const listener = jest.fn();
|
|
196
|
-
const unsubscribe = await Amply.addDeepLinkListener(listener);
|
|
197
|
-
expect(mockNativeModule.registerDeepLinkListener).toHaveBeenCalledTimes(1);
|
|
198
|
-
expect(mockNativeModule.onDeepLink).toHaveBeenCalledWith(listener);
|
|
199
|
-
await Amply.addDeepLinkListener(() => { });
|
|
200
|
-
expect(mockNativeModule.registerDeepLinkListener).toHaveBeenCalledTimes(1);
|
|
201
|
-
unsubscribe();
|
|
202
|
-
expect(remove).toHaveBeenCalledTimes(1);
|
|
203
|
-
});
|
|
204
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lastCampaignTouch.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lastCampaignTouch.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import * as Amply from '../index';
|
|
2
|
-
import { __setNativeModule } from '../nativeModule';
|
|
3
|
-
const mockNativeModule = {
|
|
4
|
-
isInitialized: jest.fn(() => true),
|
|
5
|
-
getLastCampaignTouch: jest.fn(),
|
|
6
|
-
};
|
|
7
|
-
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
8
|
-
describe('getLastCampaignTouch', () => {
|
|
9
|
-
let warn;
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
__setNativeModule(mockNativeModule);
|
|
12
|
-
warn = jest.spyOn(console, 'warn').mockImplementation(() => { });
|
|
13
|
-
});
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
warn.mockRestore();
|
|
16
|
-
jest.clearAllMocks();
|
|
17
|
-
__setNativeModule(null);
|
|
18
|
-
});
|
|
19
|
-
it('passes withinMs through to the native module and returns the touch', async () => {
|
|
20
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce({
|
|
21
|
-
campaignId: 'cmp_1',
|
|
22
|
-
campaignName: 'Spring offer',
|
|
23
|
-
kind: 'shown',
|
|
24
|
-
atMs: 1760000000000,
|
|
25
|
-
});
|
|
26
|
-
const touch = await Amply.getLastCampaignTouch(ONE_HOUR_MS);
|
|
27
|
-
expect(mockNativeModule.getLastCampaignTouch).toHaveBeenCalledWith(ONE_HOUR_MS);
|
|
28
|
-
expect(touch).toEqual({
|
|
29
|
-
campaignId: 'cmp_1',
|
|
30
|
-
campaignName: 'Spring offer',
|
|
31
|
-
kind: 'shown',
|
|
32
|
-
atMs: 1760000000000,
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
it('is exposed on the default export too', async () => {
|
|
36
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce(null);
|
|
37
|
-
await expect(Amply.default.getLastCampaignTouch(0)).resolves.toBeNull();
|
|
38
|
-
});
|
|
39
|
-
it('resolves null when the native side has no touch', async () => {
|
|
40
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce(null);
|
|
41
|
-
await expect(Amply.getLastCampaignTouch(ONE_HOUR_MS)).resolves.toBeNull();
|
|
42
|
-
});
|
|
43
|
-
it('resolves null when the native side resolves undefined', async () => {
|
|
44
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce(undefined);
|
|
45
|
-
await expect(Amply.getLastCampaignTouch(ONE_HOUR_MS)).resolves.toBeNull();
|
|
46
|
-
});
|
|
47
|
-
it.each([
|
|
48
|
-
['shown', 'shown'],
|
|
49
|
-
['engaged', 'engaged'],
|
|
50
|
-
['SHOWN', 'shown'],
|
|
51
|
-
['ENGAGED', 'engaged'],
|
|
52
|
-
])('maps native kind %s to %s', async (nativeKind, expected) => {
|
|
53
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce({
|
|
54
|
-
campaignId: 'cmp_1',
|
|
55
|
-
campaignName: 'Spring offer',
|
|
56
|
-
kind: nativeKind,
|
|
57
|
-
atMs: 1,
|
|
58
|
-
});
|
|
59
|
-
const touch = await Amply.getLastCampaignTouch(ONE_HOUR_MS);
|
|
60
|
-
expect(touch === null || touch === void 0 ? void 0 : touch.kind).toBe(expected);
|
|
61
|
-
});
|
|
62
|
-
it('resolves null and warns for a kind this bridge does not know', async () => {
|
|
63
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce({
|
|
64
|
-
campaignId: 'cmp_1',
|
|
65
|
-
campaignName: 'Spring offer',
|
|
66
|
-
kind: 'clicked',
|
|
67
|
-
atMs: 1,
|
|
68
|
-
});
|
|
69
|
-
await expect(Amply.getLastCampaignTouch(ONE_HOUR_MS)).resolves.toBeNull();
|
|
70
|
-
expect(warn).toHaveBeenCalledWith(expect.stringContaining('getLastCampaignTouch'), expect.anything());
|
|
71
|
-
});
|
|
72
|
-
it.each([
|
|
73
|
-
['a missing campaignId', { campaignName: 'x', kind: 'shown', atMs: 1 }],
|
|
74
|
-
['a non-numeric atMs', { campaignId: 'c', campaignName: 'x', kind: 'shown', atMs: '1' }],
|
|
75
|
-
])('resolves null for a payload with %s', async (_label, payload) => {
|
|
76
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce(payload);
|
|
77
|
-
await expect(Amply.getLastCampaignTouch(ONE_HOUR_MS)).resolves.toBeNull();
|
|
78
|
-
});
|
|
79
|
-
it('keeps an empty campaign name rather than dropping the touch', async () => {
|
|
80
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce({
|
|
81
|
-
campaignId: 'cmp_1',
|
|
82
|
-
campaignName: '',
|
|
83
|
-
kind: 'engaged',
|
|
84
|
-
atMs: 5,
|
|
85
|
-
});
|
|
86
|
-
await expect(Amply.getLastCampaignTouch(ONE_HOUR_MS)).resolves.toEqual({
|
|
87
|
-
campaignId: 'cmp_1',
|
|
88
|
-
campaignName: '',
|
|
89
|
-
kind: 'engaged',
|
|
90
|
-
atMs: 5,
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
it('resolves null instead of rejecting when the native call fails', async () => {
|
|
94
|
-
mockNativeModule.getLastCampaignTouch.mockRejectedValueOnce(new Error('bridge gone'));
|
|
95
|
-
await expect(Amply.getLastCampaignTouch(ONE_HOUR_MS)).resolves.toBeNull();
|
|
96
|
-
expect(warn).toHaveBeenCalled();
|
|
97
|
-
});
|
|
98
|
-
it('accepts zero', async () => {
|
|
99
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce(null);
|
|
100
|
-
await Amply.getLastCampaignTouch(0);
|
|
101
|
-
expect(mockNativeModule.getLastCampaignTouch).toHaveBeenCalledWith(0);
|
|
102
|
-
});
|
|
103
|
-
it('leaves a large window to the native clamp', async () => {
|
|
104
|
-
mockNativeModule.getLastCampaignTouch.mockResolvedValueOnce(null);
|
|
105
|
-
const ninetyDaysMs = 90 * 24 * ONE_HOUR_MS;
|
|
106
|
-
await Amply.getLastCampaignTouch(ninetyDaysMs);
|
|
107
|
-
expect(mockNativeModule.getLastCampaignTouch).toHaveBeenCalledWith(ninetyDaysMs);
|
|
108
|
-
});
|
|
109
|
-
it.each([
|
|
110
|
-
['negative', -1],
|
|
111
|
-
['NaN', Number.NaN],
|
|
112
|
-
['Infinity', Number.POSITIVE_INFINITY],
|
|
113
|
-
['a string', '3600000'],
|
|
114
|
-
['undefined', undefined],
|
|
115
|
-
])('rejects with a RangeError for %s and never calls native', async (_label, value) => {
|
|
116
|
-
await expect(Amply.getLastCampaignTouch(value)).rejects.toBeInstanceOf(RangeError);
|
|
117
|
-
expect(mockNativeModule.getLastCampaignTouch).not.toHaveBeenCalled();
|
|
118
|
-
});
|
|
119
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"systemEventUtils.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/systemEventUtils.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { formatSystemEventLabel } from '../systemEventUtils';
|
|
2
|
-
function makeEvent(name, properties = {}) {
|
|
3
|
-
return { name, type: 'system', timestamp: Date.now(), properties };
|
|
4
|
-
}
|
|
5
|
-
describe('formatSystemEventLabel', () => {
|
|
6
|
-
describe('SessionStarted', () => {
|
|
7
|
-
it('returns "Session started (cold)" for cold start', () => {
|
|
8
|
-
const event = makeEvent('SessionStarted', { type: 'cold' });
|
|
9
|
-
expect(formatSystemEventLabel(event)).toBe('Session started (cold)');
|
|
10
|
-
});
|
|
11
|
-
it('returns "Session started (warm)" for warm start', () => {
|
|
12
|
-
const event = makeEvent('SessionStarted', { type: 'warm' });
|
|
13
|
-
expect(formatSystemEventLabel(event)).toBe('Session started (warm)');
|
|
14
|
-
});
|
|
15
|
-
it('returns "Session started" when type is absent', () => {
|
|
16
|
-
const event = makeEvent('SessionStarted');
|
|
17
|
-
expect(formatSystemEventLabel(event)).toBe('Session started');
|
|
18
|
-
});
|
|
19
|
-
it('handles unexpected type values gracefully', () => {
|
|
20
|
-
const event = makeEvent('SessionStarted', { type: 'unknown' });
|
|
21
|
-
expect(formatSystemEventLabel(event)).toBe('Session started (unknown)');
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
describe('other events', () => {
|
|
25
|
-
it('formats CampaignShown with campaignId and source', () => {
|
|
26
|
-
const event = makeEvent('CampaignShown', {
|
|
27
|
-
campaignId: 'abc',
|
|
28
|
-
source: 'click',
|
|
29
|
-
});
|
|
30
|
-
expect(formatSystemEventLabel(event)).toBe('Campaign shown (abc) via click');
|
|
31
|
-
});
|
|
32
|
-
it('names the campaign in CampaignShown when the SDK sends campaignName', () => {
|
|
33
|
-
const event = makeEvent('CampaignShown', {
|
|
34
|
-
campaignId: 'abc',
|
|
35
|
-
campaignName: 'Spring offer',
|
|
36
|
-
source: 'click',
|
|
37
|
-
});
|
|
38
|
-
expect(formatSystemEventLabel(event)).toBe('Campaign shown "Spring offer" (abc) via click');
|
|
39
|
-
});
|
|
40
|
-
it('ignores an empty campaignName in CampaignShown', () => {
|
|
41
|
-
const event = makeEvent('CampaignShown', {
|
|
42
|
-
campaignId: 'abc',
|
|
43
|
-
campaignName: '',
|
|
44
|
-
source: 'click',
|
|
45
|
-
});
|
|
46
|
-
expect(formatSystemEventLabel(event)).toBe('Campaign shown (abc) via click');
|
|
47
|
-
});
|
|
48
|
-
it('formats EventTriggered with source event', () => {
|
|
49
|
-
const event = makeEvent('EventTriggered', { sourceEvent: 'purchase' });
|
|
50
|
-
expect(formatSystemEventLabel(event)).toBe('Event triggered (purchase)');
|
|
51
|
-
});
|
|
52
|
-
it('formats ConfigFetchFinished with campaign count', () => {
|
|
53
|
-
const event = makeEvent('ConfigFetchFinished', {
|
|
54
|
-
success: true,
|
|
55
|
-
campaignCount: 3,
|
|
56
|
-
});
|
|
57
|
-
expect(formatSystemEventLabel(event)).toBe('Config fetch finished (3 campaigns)');
|
|
58
|
-
});
|
|
59
|
-
it('formats ConfigFetchFinished failure', () => {
|
|
60
|
-
const event = makeEvent('ConfigFetchFinished', { success: false });
|
|
61
|
-
expect(formatSystemEventLabel(event)).toBe('Config fetch failed');
|
|
62
|
-
});
|
|
63
|
-
it('returns default label for SessionFinished', () => {
|
|
64
|
-
const event = makeEvent('SessionFinished');
|
|
65
|
-
expect(formatSystemEventLabel(event)).toBe('Session finished');
|
|
66
|
-
});
|
|
67
|
-
it('returns fallback for unknown events', () => {
|
|
68
|
-
const event = makeEvent('UnknownEvent');
|
|
69
|
-
expect(formatSystemEventLabel(event)).toBe('System event UnknownEvent');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
});
|