@frak-labs/core-sdk 0.1.1 → 0.2.0-beta.7898df5b
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/README.md +58 -0
- package/cdn/bundle.js +14 -0
- package/dist/actions.cjs +1 -1
- package/dist/actions.d.cts +3 -3
- package/dist/actions.d.ts +3 -3
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.cts +4 -6
- package/dist/bundle.d.ts +4 -6
- package/dist/bundle.js +1 -1
- package/dist/computeLegacyProductId-CCAZvLa5.d.cts +537 -0
- package/dist/computeLegacyProductId-b5cUWdAm.d.ts +537 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -1
- package/dist/{openSso-D--Airj6.d.cts → openSso-B0g7-807.d.cts} +173 -136
- package/dist/{openSso-DsKJ4y0j.d.ts → openSso-CMzwvaCa.d.ts} +173 -136
- package/dist/setupClient-BICl5fdX.js +13 -0
- package/dist/setupClient-nl8Dhh4V.cjs +13 -0
- package/dist/siweAuthenticate-BWmI2_TN.cjs +1 -0
- package/dist/{index-d8xS4ryI.d.ts → siweAuthenticate-CVigMOxz.d.cts} +113 -92
- package/dist/{index-C6FxkWPC.d.cts → siweAuthenticate-CnCZ7mok.d.ts} +113 -92
- package/dist/siweAuthenticate-zczqxm0a.js +1 -0
- package/dist/trackEvent-CeLFVzZn.js +1 -0
- package/dist/trackEvent-Ew5r5zfI.cjs +1 -0
- package/package.json +11 -22
- package/src/actions/displayEmbeddedWallet.ts +1 -0
- package/src/actions/displayModal.test.ts +12 -11
- package/src/actions/displayModal.ts +7 -18
- package/src/actions/ensureIdentity.ts +68 -0
- package/src/actions/{getProductInformation.test.ts → getMerchantInformation.test.ts} +33 -50
- package/src/actions/getMerchantInformation.ts +16 -0
- package/src/actions/index.ts +3 -2
- package/src/actions/openSso.ts +4 -2
- package/src/actions/referral/processReferral.test.ts +117 -242
- package/src/actions/referral/processReferral.ts +134 -204
- package/src/actions/referral/referralInteraction.test.ts +4 -12
- package/src/actions/referral/referralInteraction.ts +3 -13
- package/src/actions/sendInteraction.ts +46 -22
- package/src/actions/trackPurchaseStatus.test.ts +354 -141
- package/src/actions/trackPurchaseStatus.ts +48 -11
- package/src/actions/watchWalletStatus.ts +2 -3
- package/src/actions/wrapper/modalBuilder.test.ts +0 -14
- package/src/actions/wrapper/modalBuilder.ts +3 -12
- package/src/bundle.ts +0 -1
- package/src/clients/createIFrameFrakClient.ts +10 -5
- package/src/clients/transports/iframeLifecycleManager.test.ts +163 -4
- package/src/clients/transports/iframeLifecycleManager.ts +172 -33
- package/src/constants/interactionTypes.ts +12 -41
- package/src/index.ts +27 -16
- package/src/types/config.ts +6 -0
- package/src/types/context.ts +48 -6
- package/src/types/index.ts +15 -11
- package/src/types/lifecycle/client.ts +24 -1
- package/src/types/lifecycle/iframe.ts +6 -0
- package/src/types/rpc/displayModal.ts +2 -4
- package/src/types/rpc/embedded/index.ts +2 -2
- package/src/types/rpc/interaction.ts +31 -39
- package/src/types/rpc/merchantInformation.ts +77 -0
- package/src/types/rpc/modal/index.ts +0 -4
- package/src/types/rpc/modal/login.ts +5 -1
- package/src/types/rpc/walletStatus.ts +1 -7
- package/src/types/rpc.ts +22 -30
- package/src/types/tracking.ts +31 -0
- package/src/utils/FrakContext.test.ts +270 -186
- package/src/utils/FrakContext.ts +78 -56
- package/src/utils/backendUrl.test.ts +83 -0
- package/src/utils/backendUrl.ts +62 -0
- package/src/utils/clientId.test.ts +41 -0
- package/src/utils/clientId.ts +43 -0
- package/src/utils/compression/compress.test.ts +1 -1
- package/src/utils/compression/compress.ts +2 -2
- package/src/utils/compression/decompress.test.ts +8 -4
- package/src/utils/compression/decompress.ts +2 -2
- package/src/utils/{computeProductId.ts → computeLegacyProductId.ts} +2 -2
- package/src/utils/constants.ts +5 -0
- package/src/utils/deepLinkWithFallback.test.ts +243 -0
- package/src/utils/deepLinkWithFallback.ts +103 -0
- package/src/utils/formatAmount.ts +6 -0
- package/src/utils/iframeHelper.test.ts +18 -5
- package/src/utils/iframeHelper.ts +10 -3
- package/src/utils/index.ts +16 -1
- package/src/utils/merchantId.test.ts +653 -0
- package/src/utils/merchantId.ts +143 -0
- package/src/utils/sso.ts +18 -11
- package/src/utils/trackEvent.test.ts +23 -5
- package/src/utils/trackEvent.ts +13 -0
- package/cdn/bundle.iife.js +0 -14
- package/dist/actions-B5j-i1p0.cjs +0 -1
- package/dist/actions-q090Z0oR.js +0 -1
- package/dist/index-7OZ39x1U.d.ts +0 -195
- package/dist/index-CRsQWnTs.d.cts +0 -351
- package/dist/index-Ck1hudEi.d.ts +0 -351
- package/dist/index-zDq-VlKx.d.cts +0 -195
- package/dist/interaction-DMJ3ZfaF.d.cts +0 -45
- package/dist/interaction-KX1h9a7V.d.ts +0 -45
- package/dist/interactions-DnfM3oe0.js +0 -1
- package/dist/interactions-EIXhNLf6.cjs +0 -1
- package/dist/interactions.cjs +0 -1
- package/dist/interactions.d.cts +0 -2
- package/dist/interactions.d.ts +0 -2
- package/dist/interactions.js +0 -1
- package/dist/productTypes-BUkXJKZ7.cjs +0 -1
- package/dist/productTypes-CGb1MmBF.js +0 -1
- package/dist/src-1LQ4eLq5.js +0 -13
- package/dist/src-hW71KjPN.cjs +0 -13
- package/dist/trackEvent-CHnYa85W.js +0 -1
- package/dist/trackEvent-GuQm_1Nm.cjs +0 -1
- package/src/actions/getProductInformation.ts +0 -14
- package/src/actions/openSso.test.ts +0 -407
- package/src/actions/sendInteraction.test.ts +0 -219
- package/src/constants/interactionTypes.test.ts +0 -128
- package/src/constants/productTypes.test.ts +0 -130
- package/src/constants/productTypes.ts +0 -33
- package/src/interactions/index.ts +0 -5
- package/src/interactions/pressEncoder.test.ts +0 -215
- package/src/interactions/pressEncoder.ts +0 -53
- package/src/interactions/purchaseEncoder.test.ts +0 -291
- package/src/interactions/purchaseEncoder.ts +0 -99
- package/src/interactions/referralEncoder.test.ts +0 -170
- package/src/interactions/referralEncoder.ts +0 -47
- package/src/interactions/retailEncoder.test.ts +0 -107
- package/src/interactions/retailEncoder.ts +0 -37
- package/src/interactions/webshopEncoder.test.ts +0 -56
- package/src/interactions/webshopEncoder.ts +0 -30
- package/src/types/rpc/modal/openSession.ts +0 -25
- package/src/types/rpc/productInformation.ts +0 -59
- package/src/utils/computeProductId.test.ts +0 -80
- package/src/utils/sso.test.ts +0 -361
|
@@ -1,276 +1,401 @@
|
|
|
1
|
-
|
|
2
|
-
* Tests for trackPurchaseStatus action
|
|
3
|
-
* Tests webhook registration for purchase tracking
|
|
4
|
-
*/
|
|
5
|
-
|
|
1
|
+
import { vi } from "vitest";
|
|
6
2
|
import {
|
|
7
3
|
afterEach,
|
|
8
4
|
beforeEach,
|
|
9
5
|
describe,
|
|
10
6
|
expect,
|
|
11
|
-
|
|
12
|
-
vi,
|
|
7
|
+
test,
|
|
13
8
|
} from "../../tests/vitest-fixtures";
|
|
9
|
+
|
|
10
|
+
vi.mock("../utils/clientId", () => ({
|
|
11
|
+
getClientId: vi.fn().mockReturnValue("test-client-id"),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock("../utils/merchantId", () => ({
|
|
15
|
+
fetchMerchantId: vi.fn().mockResolvedValue(undefined),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
import { getClientId } from "../utils/clientId";
|
|
19
|
+
import { fetchMerchantId } from "../utils/merchantId";
|
|
14
20
|
import { trackPurchaseStatus } from "./trackPurchaseStatus";
|
|
15
21
|
|
|
16
|
-
describe("trackPurchaseStatus", () => {
|
|
22
|
+
describe.sequential("trackPurchaseStatus", () => {
|
|
23
|
+
const TRACK_PURCHASE_URL = "https://backend.frak.id/user/track/purchase";
|
|
24
|
+
|
|
17
25
|
let mockSessionStorage: {
|
|
18
26
|
getItem: ReturnType<typeof vi.fn>;
|
|
19
27
|
setItem: ReturnType<typeof vi.fn>;
|
|
20
28
|
removeItem: ReturnType<typeof vi.fn>;
|
|
21
29
|
};
|
|
22
|
-
let
|
|
23
|
-
|
|
30
|
+
let mockLocalStorage: {
|
|
31
|
+
getItem: ReturnType<typeof vi.fn>;
|
|
32
|
+
setItem: ReturnType<typeof vi.fn>;
|
|
33
|
+
removeItem: ReturnType<typeof vi.fn>;
|
|
34
|
+
};
|
|
35
|
+
let fetchSpy: ReturnType<typeof vi.fn>;
|
|
36
|
+
let consoleWarnSpy: ReturnType<typeof vi.spyOn>;
|
|
37
|
+
|
|
38
|
+
function setupStorage(values: {
|
|
39
|
+
interactionToken?: string | null;
|
|
40
|
+
merchantId?: string | null;
|
|
41
|
+
clientId?: string | null;
|
|
42
|
+
}) {
|
|
43
|
+
mockSessionStorage.getItem.mockImplementation((key: string) => {
|
|
44
|
+
if (key === "frak-wallet-interaction-token") {
|
|
45
|
+
return values.interactionToken ?? null;
|
|
46
|
+
}
|
|
47
|
+
if (key === "frak-merchant-id") {
|
|
48
|
+
return values.merchantId ?? null;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
mockLocalStorage.getItem.mockImplementation((key: string) => {
|
|
54
|
+
if (key === "frak-client-id") {
|
|
55
|
+
return values.clientId ?? null;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getTrackingRequests() {
|
|
62
|
+
return fetchSpy.mock.calls.filter(
|
|
63
|
+
([url]) => url === TRACK_PURCHASE_URL
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getLastTrackingRequest() {
|
|
68
|
+
return getTrackingRequests().at(-1);
|
|
69
|
+
}
|
|
24
70
|
|
|
25
71
|
beforeEach(() => {
|
|
26
|
-
// Mock sessionStorage
|
|
27
72
|
mockSessionStorage = {
|
|
28
73
|
getItem: vi.fn(),
|
|
29
74
|
setItem: vi.fn(),
|
|
30
75
|
removeItem: vi.fn(),
|
|
31
76
|
};
|
|
77
|
+
|
|
78
|
+
mockLocalStorage = {
|
|
79
|
+
getItem: vi.fn(),
|
|
80
|
+
setItem: vi.fn(),
|
|
81
|
+
removeItem: vi.fn(),
|
|
82
|
+
};
|
|
83
|
+
|
|
32
84
|
Object.defineProperty(window, "sessionStorage", {
|
|
33
85
|
value: mockSessionStorage,
|
|
34
86
|
writable: true,
|
|
35
87
|
configurable: true,
|
|
36
88
|
});
|
|
37
89
|
|
|
38
|
-
|
|
90
|
+
Object.defineProperty(window, "localStorage", {
|
|
91
|
+
value: mockLocalStorage,
|
|
92
|
+
writable: true,
|
|
93
|
+
configurable: true,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
setupStorage({
|
|
97
|
+
interactionToken: "token-123",
|
|
98
|
+
merchantId: null,
|
|
99
|
+
clientId: "test-client-id",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
vi.mocked(getClientId).mockReturnValue("test-client-id");
|
|
103
|
+
vi.mocked(fetchMerchantId).mockResolvedValue(undefined);
|
|
104
|
+
|
|
39
105
|
fetchSpy = vi.fn().mockResolvedValue({
|
|
40
106
|
ok: true,
|
|
41
107
|
status: 200,
|
|
42
108
|
});
|
|
43
|
-
global.fetch = fetchSpy;
|
|
109
|
+
global.fetch = fetchSpy as typeof fetch;
|
|
44
110
|
|
|
45
|
-
// Mock console.warn
|
|
46
111
|
consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
47
112
|
});
|
|
48
113
|
|
|
49
114
|
afterEach(() => {
|
|
50
|
-
vi.clearAllMocks();
|
|
51
115
|
consoleWarnSpy.mockRestore();
|
|
116
|
+
vi.clearAllMocks();
|
|
52
117
|
});
|
|
53
118
|
|
|
54
119
|
describe("successful tracking", () => {
|
|
55
|
-
|
|
56
|
-
|
|
120
|
+
test("should send POST request with correct parameters including merchantId", async () => {
|
|
121
|
+
const callCountBefore = getTrackingRequests().length;
|
|
57
122
|
|
|
58
123
|
await trackPurchaseStatus({
|
|
59
124
|
customerId: "cust-456",
|
|
60
125
|
orderId: "order-789",
|
|
61
126
|
token: "purchase-token",
|
|
127
|
+
merchantId: "merchant-explicit",
|
|
62
128
|
});
|
|
63
129
|
|
|
64
|
-
expect(
|
|
65
|
-
|
|
130
|
+
expect(getTrackingRequests().length).toBe(callCountBefore + 1);
|
|
131
|
+
expect(getLastTrackingRequest()).toEqual([
|
|
132
|
+
TRACK_PURCHASE_URL,
|
|
66
133
|
{
|
|
67
134
|
method: "POST",
|
|
68
135
|
headers: {
|
|
69
136
|
Accept: "application/json",
|
|
70
137
|
"Content-Type": "application/json",
|
|
71
138
|
"x-wallet-sdk-auth": "token-123",
|
|
139
|
+
"x-frak-client-id": "test-client-id",
|
|
72
140
|
},
|
|
73
141
|
body: JSON.stringify({
|
|
74
142
|
customerId: "cust-456",
|
|
75
143
|
orderId: "order-789",
|
|
76
144
|
token: "purchase-token",
|
|
145
|
+
merchantId: "merchant-explicit",
|
|
77
146
|
}),
|
|
78
|
-
}
|
|
79
|
-
);
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
80
149
|
});
|
|
81
150
|
|
|
82
|
-
|
|
83
|
-
|
|
151
|
+
test("should include x-frak-client-id header", async () => {
|
|
152
|
+
setupStorage({
|
|
153
|
+
interactionToken: null,
|
|
154
|
+
merchantId: null,
|
|
155
|
+
clientId: "test-client-id",
|
|
156
|
+
});
|
|
84
157
|
|
|
85
158
|
await trackPurchaseStatus({
|
|
86
159
|
customerId: "cust-1",
|
|
87
160
|
orderId: "order-1",
|
|
88
161
|
token: "token-1",
|
|
162
|
+
merchantId: "merchant-1",
|
|
89
163
|
});
|
|
90
164
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expect(
|
|
165
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
166
|
+
headers: Record<string, string>;
|
|
167
|
+
};
|
|
168
|
+
expect(requestInit.headers).toEqual({
|
|
169
|
+
Accept: "application/json",
|
|
170
|
+
"Content-Type": "application/json",
|
|
171
|
+
"x-frak-client-id": "test-client-id",
|
|
172
|
+
});
|
|
95
173
|
});
|
|
96
174
|
|
|
97
|
-
|
|
98
|
-
mockSessionStorage.getItem.mockReturnValue("token-123");
|
|
99
|
-
|
|
175
|
+
test("should include x-wallet-sdk-auth header when interaction token exists", async () => {
|
|
100
176
|
await trackPurchaseStatus({
|
|
101
|
-
customerId:
|
|
102
|
-
orderId: "order-
|
|
103
|
-
token: "
|
|
177
|
+
customerId: "cust-1",
|
|
178
|
+
orderId: "order-1",
|
|
179
|
+
token: "token-1",
|
|
180
|
+
merchantId: "merchant-1",
|
|
104
181
|
});
|
|
105
182
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
183
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
184
|
+
headers: Record<string, string>;
|
|
185
|
+
};
|
|
186
|
+
expect(requestInit.headers).toEqual({
|
|
187
|
+
Accept: "application/json",
|
|
188
|
+
"Content-Type": "application/json",
|
|
189
|
+
"x-wallet-sdk-auth": "token-123",
|
|
190
|
+
"x-frak-client-id": "test-client-id",
|
|
191
|
+
});
|
|
116
192
|
});
|
|
117
193
|
|
|
118
|
-
|
|
119
|
-
mockSessionStorage.getItem.mockReturnValue("token-123");
|
|
120
|
-
|
|
194
|
+
test("should handle numeric customerId and orderId", async () => {
|
|
121
195
|
await trackPurchaseStatus({
|
|
122
|
-
customerId:
|
|
196
|
+
customerId: 12345,
|
|
123
197
|
orderId: 67890,
|
|
124
198
|
token: "purchase-token",
|
|
199
|
+
merchantId: "merchant-1",
|
|
125
200
|
});
|
|
126
201
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
202
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
203
|
+
body: string;
|
|
204
|
+
};
|
|
205
|
+
expect(requestInit.body).toBe(
|
|
206
|
+
JSON.stringify({
|
|
207
|
+
customerId: 12345,
|
|
208
|
+
orderId: 67890,
|
|
209
|
+
token: "purchase-token",
|
|
210
|
+
merchantId: "merchant-1",
|
|
135
211
|
})
|
|
136
212
|
);
|
|
137
213
|
});
|
|
138
214
|
|
|
139
|
-
|
|
140
|
-
mockSessionStorage.getItem.mockReturnValue("token-123");
|
|
141
|
-
|
|
215
|
+
test("should use new endpoint URL /user/track/purchase", async () => {
|
|
142
216
|
await trackPurchaseStatus({
|
|
143
|
-
customerId:
|
|
144
|
-
orderId:
|
|
145
|
-
token: "
|
|
217
|
+
customerId: "cust-1",
|
|
218
|
+
orderId: "order-1",
|
|
219
|
+
token: "token-1",
|
|
220
|
+
merchantId: "merchant-1",
|
|
146
221
|
});
|
|
147
222
|
|
|
148
|
-
expect(
|
|
149
|
-
expect.any(String),
|
|
150
|
-
expect.objectContaining({
|
|
151
|
-
body: JSON.stringify({
|
|
152
|
-
customerId: 12345,
|
|
153
|
-
orderId: 67890,
|
|
154
|
-
token: "purchase-token",
|
|
155
|
-
}),
|
|
156
|
-
})
|
|
157
|
-
);
|
|
223
|
+
expect(getLastTrackingRequest()?.[0]).toBe(TRACK_PURCHASE_URL);
|
|
158
224
|
});
|
|
159
225
|
});
|
|
160
226
|
|
|
161
|
-
describe("
|
|
162
|
-
|
|
163
|
-
|
|
227
|
+
describe("merchantId resolution", () => {
|
|
228
|
+
test("should resolve merchantId from explicit param first", async () => {
|
|
229
|
+
setupStorage({
|
|
230
|
+
interactionToken: "token-123",
|
|
231
|
+
merchantId: "session-merchant-id",
|
|
232
|
+
clientId: "test-client-id",
|
|
233
|
+
});
|
|
234
|
+
vi.mocked(fetchMerchantId).mockResolvedValue("fetched-merchant-id");
|
|
235
|
+
const merchantLookupCallsBefore =
|
|
236
|
+
vi.mocked(fetchMerchantId).mock.calls.length;
|
|
164
237
|
|
|
165
238
|
await trackPurchaseStatus({
|
|
166
|
-
customerId: "cust-
|
|
167
|
-
orderId: "order-
|
|
168
|
-
token: "
|
|
239
|
+
customerId: "cust-1",
|
|
240
|
+
orderId: "order-1",
|
|
241
|
+
token: "token-1",
|
|
242
|
+
merchantId: "explicit-merchant-id",
|
|
169
243
|
});
|
|
170
244
|
|
|
171
|
-
|
|
172
|
-
|
|
245
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
246
|
+
body: string;
|
|
247
|
+
};
|
|
248
|
+
expect(requestInit.body).toBe(
|
|
249
|
+
JSON.stringify({
|
|
250
|
+
customerId: "cust-1",
|
|
251
|
+
orderId: "order-1",
|
|
252
|
+
token: "token-1",
|
|
253
|
+
merchantId: "explicit-merchant-id",
|
|
254
|
+
})
|
|
255
|
+
);
|
|
256
|
+
expect(vi.mocked(fetchMerchantId).mock.calls.length).toBe(
|
|
257
|
+
merchantLookupCallsBefore
|
|
173
258
|
);
|
|
174
259
|
});
|
|
175
260
|
|
|
176
|
-
|
|
177
|
-
|
|
261
|
+
test("should fall back to sessionStorage for merchantId", async () => {
|
|
262
|
+
setupStorage({
|
|
263
|
+
interactionToken: "token-123",
|
|
264
|
+
merchantId: "session-merchant-id",
|
|
265
|
+
clientId: "test-client-id",
|
|
266
|
+
});
|
|
267
|
+
const merchantLookupCallsBefore =
|
|
268
|
+
vi.mocked(fetchMerchantId).mock.calls.length;
|
|
178
269
|
|
|
179
270
|
await trackPurchaseStatus({
|
|
180
|
-
customerId: "cust-
|
|
181
|
-
orderId: "order-
|
|
182
|
-
token: "
|
|
271
|
+
customerId: "cust-1",
|
|
272
|
+
orderId: "order-1",
|
|
273
|
+
token: "token-1",
|
|
183
274
|
});
|
|
184
275
|
|
|
185
|
-
|
|
276
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
277
|
+
body: string;
|
|
278
|
+
};
|
|
279
|
+
expect(requestInit.body).toBe(
|
|
280
|
+
JSON.stringify({
|
|
281
|
+
customerId: "cust-1",
|
|
282
|
+
orderId: "order-1",
|
|
283
|
+
token: "token-1",
|
|
284
|
+
merchantId: "session-merchant-id",
|
|
285
|
+
})
|
|
286
|
+
);
|
|
287
|
+
expect(vi.mocked(fetchMerchantId).mock.calls.length).toBe(
|
|
288
|
+
merchantLookupCallsBefore
|
|
289
|
+
);
|
|
186
290
|
});
|
|
187
291
|
|
|
188
|
-
|
|
189
|
-
|
|
292
|
+
test("should fall back to fetchMerchantId when no explicit or sessionStorage", async () => {
|
|
293
|
+
setupStorage({
|
|
294
|
+
interactionToken: "token-123",
|
|
295
|
+
merchantId: null,
|
|
296
|
+
clientId: "test-client-id",
|
|
297
|
+
});
|
|
298
|
+
vi.mocked(fetchMerchantId).mockResolvedValue("fetched-merchant-id");
|
|
190
299
|
|
|
191
300
|
await trackPurchaseStatus({
|
|
192
|
-
customerId: "cust-
|
|
193
|
-
orderId: "order-
|
|
194
|
-
token: "
|
|
301
|
+
customerId: "cust-1",
|
|
302
|
+
orderId: "order-1",
|
|
303
|
+
token: "token-1",
|
|
195
304
|
});
|
|
196
305
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
await expect(
|
|
207
|
-
trackPurchaseStatus({
|
|
208
|
-
customerId: "cust-456",
|
|
209
|
-
orderId: "order-789",
|
|
210
|
-
token: "purchase-token",
|
|
306
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
307
|
+
body: string;
|
|
308
|
+
};
|
|
309
|
+
expect(requestInit.body).toBe(
|
|
310
|
+
JSON.stringify({
|
|
311
|
+
customerId: "cust-1",
|
|
312
|
+
orderId: "order-1",
|
|
313
|
+
token: "token-1",
|
|
314
|
+
merchantId: "fetched-merchant-id",
|
|
211
315
|
})
|
|
212
|
-
)
|
|
316
|
+
);
|
|
213
317
|
});
|
|
214
318
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
319
|
+
test("should warn and skip when no merchantId available", async () => {
|
|
320
|
+
setupStorage({
|
|
321
|
+
interactionToken: "token-123",
|
|
322
|
+
merchantId: null,
|
|
323
|
+
clientId: "test-client-id",
|
|
220
324
|
});
|
|
325
|
+
vi.mocked(fetchMerchantId).mockResolvedValue(undefined);
|
|
326
|
+
const callCountBefore = getTrackingRequests().length;
|
|
221
327
|
|
|
222
|
-
// Function doesn't check response, so it should complete
|
|
223
328
|
await trackPurchaseStatus({
|
|
224
|
-
customerId: "cust-
|
|
225
|
-
orderId: "order-
|
|
226
|
-
token: "
|
|
329
|
+
customerId: "cust-1",
|
|
330
|
+
orderId: "order-1",
|
|
331
|
+
token: "token-1",
|
|
227
332
|
});
|
|
228
333
|
|
|
229
|
-
expect(
|
|
334
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
335
|
+
"[Frak] No merchant id found, skipping purchase check"
|
|
336
|
+
);
|
|
337
|
+
expect(getTrackingRequests().length).toBe(callCountBefore);
|
|
230
338
|
});
|
|
231
339
|
});
|
|
232
340
|
|
|
233
|
-
describe("
|
|
234
|
-
|
|
235
|
-
|
|
341
|
+
describe("anonymous user support", () => {
|
|
342
|
+
test("should send request with only x-frak-client-id when no interaction token", async () => {
|
|
343
|
+
setupStorage({
|
|
344
|
+
interactionToken: null,
|
|
345
|
+
merchantId: null,
|
|
346
|
+
clientId: "test-client-id",
|
|
347
|
+
});
|
|
236
348
|
|
|
237
349
|
await trackPurchaseStatus({
|
|
238
350
|
customerId: "cust-1",
|
|
239
351
|
orderId: "order-1",
|
|
240
352
|
token: "token-1",
|
|
353
|
+
merchantId: "merchant-1",
|
|
241
354
|
});
|
|
242
355
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
})
|
|
252
|
-
);
|
|
356
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
357
|
+
headers: Record<string, string>;
|
|
358
|
+
};
|
|
359
|
+
expect(requestInit.headers).toEqual({
|
|
360
|
+
Accept: "application/json",
|
|
361
|
+
"Content-Type": "application/json",
|
|
362
|
+
"x-frak-client-id": "test-client-id",
|
|
363
|
+
});
|
|
253
364
|
});
|
|
254
365
|
|
|
255
|
-
|
|
256
|
-
|
|
366
|
+
test("should send request with both headers when both available", async () => {
|
|
367
|
+
setupStorage({
|
|
368
|
+
interactionToken: "token-123",
|
|
369
|
+
merchantId: null,
|
|
370
|
+
clientId: "test-client-id",
|
|
371
|
+
});
|
|
257
372
|
|
|
258
373
|
await trackPurchaseStatus({
|
|
259
374
|
customerId: "cust-1",
|
|
260
375
|
orderId: "order-1",
|
|
261
376
|
token: "token-1",
|
|
377
|
+
merchantId: "merchant-1",
|
|
262
378
|
});
|
|
263
379
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
380
|
+
const requestInit = getLastTrackingRequest()?.[1] as {
|
|
381
|
+
headers: Record<string, string>;
|
|
382
|
+
};
|
|
383
|
+
expect(requestInit.headers).toEqual({
|
|
384
|
+
Accept: "application/json",
|
|
385
|
+
"Content-Type": "application/json",
|
|
386
|
+
"x-wallet-sdk-auth": "token-123",
|
|
387
|
+
"x-frak-client-id": "test-client-id",
|
|
388
|
+
});
|
|
270
389
|
});
|
|
271
390
|
|
|
272
|
-
|
|
273
|
-
|
|
391
|
+
test("should skip when no identity available", async () => {
|
|
392
|
+
setupStorage({
|
|
393
|
+
interactionToken: null,
|
|
394
|
+
merchantId: "merchant-1",
|
|
395
|
+
clientId: null,
|
|
396
|
+
});
|
|
397
|
+
vi.mocked(getClientId).mockReturnValue("");
|
|
398
|
+
const callCountBefore = getTrackingRequests().length;
|
|
274
399
|
|
|
275
400
|
await trackPurchaseStatus({
|
|
276
401
|
customerId: "cust-1",
|
|
@@ -278,10 +403,98 @@ describe("trackPurchaseStatus", () => {
|
|
|
278
403
|
token: "token-1",
|
|
279
404
|
});
|
|
280
405
|
|
|
281
|
-
expect(
|
|
282
|
-
"
|
|
283
|
-
|
|
406
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
407
|
+
"[Frak] No identity found, skipping purchase check"
|
|
408
|
+
);
|
|
409
|
+
expect(getTrackingRequests().length).toBe(callCountBefore);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
describe("missing identity", () => {
|
|
414
|
+
test("should warn when no identity sources available", async () => {
|
|
415
|
+
setupStorage({
|
|
416
|
+
interactionToken: null,
|
|
417
|
+
merchantId: "merchant-1",
|
|
418
|
+
clientId: null,
|
|
419
|
+
});
|
|
420
|
+
vi.mocked(getClientId).mockReturnValue("");
|
|
421
|
+
const callCountBefore = getTrackingRequests().length;
|
|
422
|
+
|
|
423
|
+
await trackPurchaseStatus({
|
|
424
|
+
customerId: "cust-456",
|
|
425
|
+
orderId: "order-789",
|
|
426
|
+
token: "purchase-token",
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
430
|
+
"[Frak] No identity found, skipping purchase check"
|
|
284
431
|
);
|
|
432
|
+
expect(getTrackingRequests().length).toBe(callCountBefore);
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
describe("non-browser environment", () => {
|
|
437
|
+
test("should warn and skip when window is undefined", async () => {
|
|
438
|
+
const savedWindow = globalThis.window;
|
|
439
|
+
Reflect.deleteProperty(globalThis, "window");
|
|
440
|
+
const callCountBefore = getTrackingRequests().length;
|
|
441
|
+
|
|
442
|
+
try {
|
|
443
|
+
await trackPurchaseStatus({
|
|
444
|
+
customerId: "cust-1",
|
|
445
|
+
orderId: "order-1",
|
|
446
|
+
token: "token-1",
|
|
447
|
+
merchantId: "merchant-1",
|
|
448
|
+
});
|
|
449
|
+
} finally {
|
|
450
|
+
Object.defineProperty(globalThis, "window", {
|
|
451
|
+
value: savedWindow,
|
|
452
|
+
writable: true,
|
|
453
|
+
configurable: true,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
458
|
+
"[Frak] No window found, can't track purchase"
|
|
459
|
+
);
|
|
460
|
+
expect(getTrackingRequests().length).toBe(callCountBefore);
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
describe("network errors", () => {
|
|
465
|
+
test("should handle fetch rejection", async () => {
|
|
466
|
+
vi.mocked(getClientId).mockReturnValue("test-client-id");
|
|
467
|
+
setupStorage({
|
|
468
|
+
interactionToken: "token-123",
|
|
469
|
+
merchantId: null,
|
|
470
|
+
clientId: "test-client-id",
|
|
471
|
+
});
|
|
472
|
+
fetchSpy.mockRejectedValueOnce(new Error("Network error"));
|
|
473
|
+
|
|
474
|
+
await expect(
|
|
475
|
+
trackPurchaseStatus({
|
|
476
|
+
customerId: "cust-456",
|
|
477
|
+
orderId: "order-789",
|
|
478
|
+
token: "purchase-token",
|
|
479
|
+
merchantId: "merchant-1",
|
|
480
|
+
})
|
|
481
|
+
).rejects.toThrow("Network error");
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test("should handle fetch with error response", async () => {
|
|
485
|
+
fetchSpy.mockResolvedValue({
|
|
486
|
+
ok: false,
|
|
487
|
+
status: 500,
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
await trackPurchaseStatus({
|
|
491
|
+
customerId: "cust-456",
|
|
492
|
+
orderId: "order-789",
|
|
493
|
+
token: "purchase-token",
|
|
494
|
+
merchantId: "merchant-1",
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
expect(fetchSpy).toHaveBeenCalled();
|
|
285
498
|
});
|
|
286
499
|
});
|
|
287
500
|
});
|