Skip to content

Commit f06e730

Browse files
committed
test(SDK-518): add mechanical coverage ratchet for models, enums, and utils
1 parent 8f2bd91 commit f06e730

20 files changed

Lines changed: 854 additions & 0 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,5 @@ docs/
9999
.agent/
100100
.claude/
101101
.cursor/
102+
.opencode/
102103
.pi/

src/__tests__/index.test.tsx

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,116 @@ describe('public SDK surface', () => {
9595
expect(useAppStateListener).toBeDefined();
9696
expect(useDeviceOrientation).toBeDefined();
9797
});
98+
99+
describe('exported enum values', () => {
100+
it('IterableActionSource contains expected members', () => {
101+
expect(IterableActionSource.push).toBe(0);
102+
expect(IterableActionSource.appLink).toBe(1);
103+
expect(IterableActionSource.inApp).toBe(2);
104+
expect(IterableActionSource.embedded).toBe(3);
105+
});
106+
107+
it('IterableInAppCloseSource contains expected members', () => {
108+
expect(IterableInAppCloseSource.back).toBe(0);
109+
expect(IterableInAppCloseSource.link).toBe(1);
110+
expect(IterableInAppCloseSource.unknown).toBe(100);
111+
});
112+
113+
it('IterableInAppLocation contains expected members', () => {
114+
expect(IterableInAppLocation.inApp).toBe(0);
115+
expect(IterableInAppLocation.inbox).toBe(1);
116+
});
117+
118+
it('IterableInAppShowResponse contains expected members', () => {
119+
expect(IterableInAppShowResponse.show).toBe(0);
120+
expect(IterableInAppShowResponse.skip).toBe(1);
121+
});
122+
123+
it('IterableInAppTriggerType contains expected members', () => {
124+
expect(IterableInAppTriggerType.immediate).toBe(0);
125+
expect(IterableInAppTriggerType.event).toBe(1);
126+
expect(IterableInAppTriggerType.never).toBe(2);
127+
});
128+
129+
it('IterableDataRegion contains expected members', () => {
130+
expect(IterableDataRegion.US).toBe(0);
131+
expect(IterableDataRegion.EU).toBe(1);
132+
});
133+
134+
it('IterableLogLevel contains expected members', () => {
135+
expect(IterableLogLevel.error).toBe(3);
136+
expect(IterableLogLevel.debug).toBe(1);
137+
expect(IterableLogLevel.info).toBe(2);
138+
});
139+
140+
it('IterablePushPlatform contains expected members', () => {
141+
expect(IterablePushPlatform.sandbox).toBe(0);
142+
expect(IterablePushPlatform.production).toBe(1);
143+
expect(IterablePushPlatform.auto).toBe(2);
144+
});
145+
146+
it('IterableRetryBackoff contains expected members', () => {
147+
expect(IterableRetryBackoff.linear).toBe('LINEAR');
148+
expect(IterableRetryBackoff.exponential).toBe('EXPONENTIAL');
149+
});
150+
151+
it('IterableEmbeddedViewType contains expected members', () => {
152+
expect(IterableEmbeddedViewType.Banner).toBe(0);
153+
expect(IterableEmbeddedViewType.Card).toBe(1);
154+
expect(IterableEmbeddedViewType.Notification).toBe(2);
155+
});
156+
});
157+
158+
describe('exported hooks are functions', () => {
159+
it('useAppStateListener is a function', () => {
160+
expect(typeof useAppStateListener).toBe('function');
161+
});
162+
163+
it('useDeviceOrientation is a function', () => {
164+
expect(typeof useDeviceOrientation).toBe('function');
165+
});
166+
});
167+
168+
describe('exported components are valid React components', () => {
169+
it('IterableInbox is a valid React component', () => {
170+
expect(IterableInbox).toBeDefined();
171+
// React components are functions or classes (forwardRef objects expose a render fn)
172+
const type = typeof IterableInbox;
173+
expect(
174+
type === 'function' ||
175+
type === 'object' ||
176+
type === 'symbol'
177+
).toBe(true);
178+
});
179+
180+
it('IterableInboxEmptyState is a valid React component', () => {
181+
expect(IterableInboxEmptyState).toBeDefined();
182+
const type = typeof IterableInboxEmptyState;
183+
expect(
184+
type === 'function' ||
185+
type === 'object' ||
186+
type === 'symbol'
187+
).toBe(true);
188+
});
189+
190+
it('IterableInboxMessageCell is a valid React component', () => {
191+
expect(IterableInboxMessageCell).toBeDefined();
192+
const type = typeof IterableInboxMessageCell;
193+
expect(
194+
type === 'function' ||
195+
type === 'object' ||
196+
type === 'symbol'
197+
).toBe(true);
198+
});
199+
200+
it('IterableEmbeddedView is a valid React component', () => {
201+
expect(IterableEmbeddedView).toBeDefined();
202+
const type = typeof IterableEmbeddedView;
203+
expect(
204+
type === 'function' ||
205+
type === 'object' ||
206+
type === 'symbol'
207+
).toBe(true);
208+
});
209+
});
98210
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { IterableAction } from './IterableAction';
2+
3+
describe('IterableAction', () => {
4+
describe('constructor', () => {
5+
it('creates an instance with type only', () => {
6+
const action = new IterableAction('openUrl');
7+
expect(action.type).toBe('openUrl');
8+
expect(action.data).toBeUndefined();
9+
expect(action.userInput).toBeUndefined();
10+
});
11+
12+
it('creates an instance with type, data, and userInput', () => {
13+
const action = new IterableAction('openUrl', 'https://example.com', 'tap');
14+
expect(action.type).toBe('openUrl');
15+
expect(action.data).toBe('https://example.com');
16+
expect(action.userInput).toBe('tap');
17+
});
18+
});
19+
20+
describe('fromDict', () => {
21+
it('copies all fields when present', () => {
22+
const dict = new IterableAction('openUrl', 'https://example.com', 'tap');
23+
const action = IterableAction.fromDict(dict);
24+
expect(action.type).toBe('openUrl');
25+
expect(action.data).toBe('https://example.com');
26+
expect(action.userInput).toBe('tap');
27+
});
28+
29+
it('handles missing data and userInput', () => {
30+
// Simulate a payload where only type is defined — data and userInput are absent.
31+
const dict = {
32+
type: 'openUrl',
33+
} as IterableAction;
34+
35+
const action = IterableAction.fromDict(dict);
36+
37+
expect(action.type).toBe('openUrl');
38+
expect(action.data).toBeUndefined();
39+
expect(action.userInput).toBeUndefined();
40+
});
41+
42+
it('handles only data missing', () => {
43+
const dict = {
44+
type: 'openUrl',
45+
userInput: 'tap',
46+
} as IterableAction;
47+
48+
const action = IterableAction.fromDict(dict);
49+
50+
expect(action.type).toBe('openUrl');
51+
expect(action.data).toBeUndefined();
52+
expect(action.userInput).toBe('tap');
53+
});
54+
55+
it('handles only userInput missing', () => {
56+
const dict = {
57+
type: 'openUrl',
58+
data: 'https://example.com',
59+
} as IterableAction;
60+
61+
const action = IterableAction.fromDict(dict);
62+
63+
expect(action.type).toBe('openUrl');
64+
expect(action.data).toBe('https://example.com');
65+
expect(action.userInput).toBeUndefined();
66+
});
67+
});
68+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { IterableAction } from './IterableAction';
2+
import { IterableActionContext } from './IterableActionContext';
3+
import { IterableActionSource } from '../enums/IterableActionSource';
4+
5+
describe('IterableActionContext', () => {
6+
describe('constructor', () => {
7+
it('creates an instance with action and source', () => {
8+
const action = new IterableAction('openUrl', 'https://example.com');
9+
const context = new IterableActionContext(action, IterableActionSource.push);
10+
11+
expect(context.action).toBe(action);
12+
expect(context.source).toBe(IterableActionSource.push);
13+
});
14+
});
15+
16+
describe('fromDict', () => {
17+
it('creates a full instance from a complete dict', () => {
18+
const dict = new IterableActionContext(
19+
new IterableAction('openUrl', 'https://example.com', 'tap'),
20+
IterableActionSource.inApp
21+
);
22+
23+
const context = IterableActionContext.fromDict(dict);
24+
25+
expect(context.source).toBe(IterableActionSource.inApp);
26+
expect(context.action.type).toBe('openUrl');
27+
expect(context.action.data).toBe('https://example.com');
28+
expect(context.action.userInput).toBe('tap');
29+
});
30+
31+
it('handles a partial action dict with only type', () => {
32+
// Simulate a payload where the nested action only has `type` defined.
33+
const dict = {
34+
action: { type: 'openUrl' } as IterableAction,
35+
source: IterableActionSource.appLink,
36+
} as IterableActionContext;
37+
38+
const context = IterableActionContext.fromDict(dict);
39+
40+
expect(context.source).toBe(IterableActionSource.appLink);
41+
expect(context.action.type).toBe('openUrl');
42+
expect(context.action.data).toBeUndefined();
43+
expect(context.action.userInput).toBeUndefined();
44+
});
45+
46+
it('handles a partial action dict with type and data only', () => {
47+
const dict = {
48+
action: { type: 'openUrl', data: 'https://example.com' } as IterableAction,
49+
source: IterableActionSource.embedded,
50+
} as IterableActionContext;
51+
52+
const context = IterableActionContext.fromDict(dict);
53+
54+
expect(context.source).toBe(IterableActionSource.embedded);
55+
expect(context.action.type).toBe('openUrl');
56+
expect(context.action.data).toBe('https://example.com');
57+
expect(context.action.userInput).toBeUndefined();
58+
});
59+
});
60+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { IterableDataRegion } from './IterableDataRegion';
2+
3+
describe('IterableDataRegion', () => {
4+
it('contains the expected members', () => {
5+
expect(IterableDataRegion.US).toBe(0);
6+
expect(IterableDataRegion.EU).toBe(1);
7+
});
8+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { IterableLogLevel } from './IterableLogLevel';
2+
3+
describe('IterableLogLevel', () => {
4+
it('contains the expected members', () => {
5+
expect(IterableLogLevel.error).toBe(3);
6+
expect(IterableLogLevel.debug).toBe(1);
7+
expect(IterableLogLevel.info).toBe(2);
8+
});
9+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { IterablePushPlatform } from './IterablePushPlatform';
2+
3+
describe('IterablePushPlatform', () => {
4+
it('contains the expected members', () => {
5+
expect(IterablePushPlatform.sandbox).toBe(0);
6+
expect(IterablePushPlatform.production).toBe(1);
7+
expect(IterablePushPlatform.auto).toBe(2);
8+
});
9+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { IterableRetryBackoff } from './IterableRetryBackoff';
2+
3+
describe('IterableRetryBackoff', () => {
4+
it('contains the expected members', () => {
5+
expect(IterableRetryBackoff.linear).toBe('LINEAR');
6+
expect(IterableRetryBackoff.exponential).toBe('EXPONENTIAL');
7+
});
8+
});

0 commit comments

Comments
 (0)