@frak-labs/core-sdk 0.2.0 → 0.2.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/cdn/bundle.js +3 -3
- package/dist/actions.cjs +1 -1
- package/dist/actions.d.cts +2 -2
- package/dist/actions.d.ts +2 -2
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.cts +4 -4
- package/dist/bundle.d.ts +4 -4
- package/dist/bundle.js +1 -1
- package/dist/{computeLegacyProductId-Raks6FXg.d.cts → computeLegacyProductId-CCAZvLa5.d.cts} +45 -46
- package/dist/{computeLegacyProductId-BkyJ4rEY.d.ts → computeLegacyProductId-b5cUWdAm.d.ts} +45 -46
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/{openSso-BCJGchIb.d.cts → openSso-B0g7-807.d.cts} +40 -7
- package/dist/{openSso-DG-_9CED.d.ts → openSso-CMzwvaCa.d.ts} +40 -7
- package/dist/setupClient-BduY6Sym.cjs +13 -0
- package/dist/setupClient-ftmdQ-I8.js +13 -0
- package/dist/siweAuthenticate-BWmI2_TN.cjs +1 -0
- package/dist/{siweAuthenticate-Btem4QHs.d.ts → siweAuthenticate-CVigMOxz.d.cts} +28 -32
- package/dist/{siweAuthenticate-BH7Dn7nZ.d.cts → siweAuthenticate-CnCZ7mok.d.ts} +28 -32
- package/dist/siweAuthenticate-zczqxm0a.js +1 -0
- package/dist/trackEvent-CeLFVzZn.js +1 -0
- package/dist/trackEvent-Ew5r5zfI.cjs +1 -0
- package/package.json +1 -1
- package/src/actions/referral/processReferral.test.ts +109 -125
- package/src/actions/referral/processReferral.ts +134 -180
- package/src/actions/referral/referralInteraction.test.ts +3 -5
- package/src/actions/referral/referralInteraction.ts +2 -7
- package/src/index.ts +3 -0
- package/src/types/context.ts +48 -6
- package/src/types/index.ts +2 -1
- package/src/types/rpc/interaction.ts +5 -0
- package/src/types/tracking.ts +5 -34
- package/src/utils/FrakContext.test.ts +270 -186
- package/src/utils/FrakContext.ts +78 -56
- package/dist/setupClient-CQrMDGyZ.js +0 -13
- package/dist/setupClient-Ccv3XxwL.cjs +0 -13
- package/dist/siweAuthenticate-BJHbtty4.js +0 -1
- package/dist/siweAuthenticate-Cwj3HP0m.cjs +0 -1
- package/dist/trackEvent-M2RLTQ2p.js +0 -1
- package/dist/trackEvent-T_R9ER2S.cjs +0 -1
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for FrakContextManager utility
|
|
3
|
-
* Tests Frak context compression, URL parsing, and management
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import { mockWindowHistory } from "@frak-labs/test-foundation";
|
|
7
2
|
import type { Address } from "viem";
|
|
8
3
|
import {
|
|
@@ -13,7 +8,7 @@ import {
|
|
|
13
8
|
it,
|
|
14
9
|
vi,
|
|
15
10
|
} from "../../tests/vitest-fixtures";
|
|
16
|
-
import type {
|
|
11
|
+
import type { FrakContextV1, FrakContextV2 } from "../types";
|
|
17
12
|
import { FrakContextManager } from "./FrakContext";
|
|
18
13
|
|
|
19
14
|
describe("FrakContextManager", () => {
|
|
@@ -29,244 +24,316 @@ describe("FrakContextManager", () => {
|
|
|
29
24
|
consoleErrorSpy.mockRestore();
|
|
30
25
|
});
|
|
31
26
|
|
|
32
|
-
describe("
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
describe("V2 context", () => {
|
|
28
|
+
const v2Context: FrakContextV2 = {
|
|
29
|
+
v: 2,
|
|
30
|
+
c: "test-client-id-uuid",
|
|
31
|
+
m: "merchant-uuid-1234",
|
|
32
|
+
t: 1709654400,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
describe("compress", () => {
|
|
36
|
+
it("should compress v2 context with all fields", () => {
|
|
37
|
+
const result = FrakContextManager.compress(v2Context);
|
|
38
|
+
|
|
39
|
+
expect(result).toBeDefined();
|
|
40
|
+
expect(typeof result).toBe("string");
|
|
41
|
+
expect(result?.length).toBeGreaterThan(0);
|
|
42
|
+
expect(result).not.toMatch(/[+/=]/);
|
|
43
|
+
});
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
it("should return undefined when v2 context is missing clientId", () => {
|
|
46
|
+
const partial = { v: 2 as const, m: "m", t: 123 };
|
|
47
|
+
const result = FrakContextManager.compress(
|
|
48
|
+
partial as FrakContextV2
|
|
49
|
+
);
|
|
50
|
+
expect(result).toBeUndefined();
|
|
51
|
+
});
|
|
39
52
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
it("should return undefined when v2 context is missing merchantId", () => {
|
|
54
|
+
const partial = { v: 2 as const, c: "c", t: 123 };
|
|
55
|
+
const result = FrakContextManager.compress(
|
|
56
|
+
partial as FrakContextV2
|
|
57
|
+
);
|
|
58
|
+
expect(result).toBeUndefined();
|
|
59
|
+
});
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
61
|
+
it("should return undefined when v2 context is missing timestamp", () => {
|
|
62
|
+
const partial = { v: 2 as const, c: "c", m: "m" };
|
|
63
|
+
const result = FrakContextManager.compress(
|
|
64
|
+
partial as FrakContextV2
|
|
65
|
+
);
|
|
66
|
+
expect(result).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
49
69
|
|
|
50
|
-
|
|
70
|
+
describe("decompress", () => {
|
|
71
|
+
it("should round-trip compress and decompress v2 context", () => {
|
|
72
|
+
const compressed = FrakContextManager.compress(v2Context);
|
|
73
|
+
const decompressed = FrakContextManager.decompress(compressed);
|
|
51
74
|
|
|
52
|
-
|
|
75
|
+
expect(decompressed).toEqual(v2Context);
|
|
76
|
+
});
|
|
53
77
|
});
|
|
54
78
|
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
describe("parse", () => {
|
|
80
|
+
it("should parse URL with v2 fCtx parameter", () => {
|
|
81
|
+
const compressed = FrakContextManager.compress(v2Context);
|
|
82
|
+
const url = `https://example.com?fCtx=${compressed}`;
|
|
57
83
|
|
|
58
|
-
|
|
84
|
+
const result = FrakContextManager.parse({ url });
|
|
85
|
+
|
|
86
|
+
expect(result).toBeDefined();
|
|
87
|
+
expect(result).toHaveProperty("v", 2);
|
|
88
|
+
const v2 = result as FrakContextV2;
|
|
89
|
+
expect(v2.c).toBe("test-client-id-uuid");
|
|
90
|
+
expect(v2.m).toBe("merchant-uuid-1234");
|
|
91
|
+
expect(v2.t).toBe(1709654400);
|
|
92
|
+
});
|
|
59
93
|
});
|
|
60
94
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
95
|
+
describe("update", () => {
|
|
96
|
+
it("should add v2 fCtx to URL", () => {
|
|
97
|
+
const url = "https://example.com";
|
|
65
98
|
|
|
66
|
-
|
|
99
|
+
const result = FrakContextManager.update({
|
|
100
|
+
url,
|
|
101
|
+
context: v2Context,
|
|
102
|
+
});
|
|
67
103
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
104
|
+
expect(result).toBeDefined();
|
|
105
|
+
expect(result).toContain("fCtx=");
|
|
106
|
+
expect(result).toContain("https://example.com");
|
|
72
107
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const originalContext: FrakContext = {
|
|
77
|
-
r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
|
|
78
|
-
};
|
|
79
|
-
const compressed = FrakContextManager.compress(originalContext);
|
|
108
|
+
const parsed = FrakContextManager.parse({ url: result! });
|
|
109
|
+
expect(parsed).toEqual(v2Context);
|
|
110
|
+
});
|
|
80
111
|
|
|
81
|
-
|
|
82
|
-
|
|
112
|
+
it("should preserve other URL parameters", () => {
|
|
113
|
+
const url = "https://example.com?foo=bar&baz=qux";
|
|
83
114
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
const result = FrakContextManager.update({
|
|
116
|
+
url,
|
|
117
|
+
context: v2Context,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(result).toContain("foo=bar");
|
|
121
|
+
expect(result).toContain("baz=qux");
|
|
122
|
+
expect(result).toContain("fCtx=");
|
|
123
|
+
});
|
|
88
124
|
});
|
|
125
|
+
});
|
|
89
126
|
|
|
90
|
-
|
|
91
|
-
|
|
127
|
+
describe("V1 backward compatibility", () => {
|
|
128
|
+
describe("compress", () => {
|
|
129
|
+
it("should compress context with referrer address", () => {
|
|
130
|
+
const context: FrakContextV1 = {
|
|
131
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
132
|
+
};
|
|
92
133
|
|
|
93
|
-
|
|
94
|
-
});
|
|
134
|
+
const result = FrakContextManager.compress(context);
|
|
95
135
|
|
|
96
|
-
|
|
97
|
-
|
|
136
|
+
expect(result).toBeDefined();
|
|
137
|
+
expect(typeof result).toBe("string");
|
|
138
|
+
expect(result?.length).toBeGreaterThan(0);
|
|
139
|
+
expect(result).not.toMatch(/[+/=]/);
|
|
140
|
+
});
|
|
98
141
|
|
|
99
|
-
|
|
100
|
-
|
|
142
|
+
it("should return undefined when context has no referrer", () => {
|
|
143
|
+
const context = {} as FrakContextV1;
|
|
101
144
|
|
|
102
|
-
|
|
103
|
-
const result = FrakContextManager.decompress(
|
|
104
|
-
"invalid-base64url!@#"
|
|
105
|
-
);
|
|
145
|
+
const result = FrakContextManager.compress(context);
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
});
|
|
147
|
+
expect(result).toBeUndefined();
|
|
148
|
+
});
|
|
110
149
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
114
|
-
};
|
|
150
|
+
it("should return undefined when context is undefined", () => {
|
|
151
|
+
const result = FrakContextManager.compress(undefined);
|
|
115
152
|
|
|
116
|
-
|
|
117
|
-
|
|
153
|
+
expect(result).toBeUndefined();
|
|
154
|
+
});
|
|
118
155
|
|
|
119
|
-
|
|
156
|
+
it("should handle compression errors gracefully", () => {
|
|
157
|
+
const invalidContext = {
|
|
158
|
+
r: "invalid-address" as Address,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const result = FrakContextManager.compress(invalidContext);
|
|
162
|
+
|
|
163
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
164
|
+
expect(result).toBeUndefined();
|
|
165
|
+
});
|
|
120
166
|
});
|
|
121
|
-
});
|
|
122
167
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const url = `https://example.com?fCtx=${compressed}`;
|
|
168
|
+
describe("decompress", () => {
|
|
169
|
+
it("should decompress valid v1 base64url context", () => {
|
|
170
|
+
const originalContext: FrakContextV1 = {
|
|
171
|
+
r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
|
|
172
|
+
};
|
|
173
|
+
const compressed = FrakContextManager.compress(originalContext);
|
|
130
174
|
|
|
131
|
-
|
|
175
|
+
const result = FrakContextManager.decompress(compressed);
|
|
132
176
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
177
|
+
expect(result).toBeDefined();
|
|
178
|
+
expect((result as FrakContextV1).r).toBe(
|
|
179
|
+
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
|
|
180
|
+
);
|
|
181
|
+
});
|
|
138
182
|
|
|
139
|
-
|
|
140
|
-
|
|
183
|
+
it("should return undefined for empty string", () => {
|
|
184
|
+
const result = FrakContextManager.decompress("");
|
|
141
185
|
|
|
142
|
-
|
|
186
|
+
expect(result).toBeUndefined();
|
|
187
|
+
});
|
|
143
188
|
|
|
144
|
-
|
|
145
|
-
|
|
189
|
+
it("should return undefined for undefined input", () => {
|
|
190
|
+
const result = FrakContextManager.decompress(undefined);
|
|
146
191
|
|
|
147
|
-
|
|
148
|
-
|
|
192
|
+
expect(result).toBeUndefined();
|
|
193
|
+
});
|
|
149
194
|
|
|
150
|
-
|
|
151
|
-
|
|
195
|
+
it("should handle decompression errors gracefully", () => {
|
|
196
|
+
const result = FrakContextManager.decompress(
|
|
197
|
+
"invalid-base64url!@#"
|
|
198
|
+
);
|
|
152
199
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
157
|
-
const compressed = FrakContextManager.compress(context);
|
|
158
|
-
const url = `https://example.com?foo=bar&fCtx=${compressed}&baz=qux`;
|
|
200
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
201
|
+
expect(result).toBeUndefined();
|
|
202
|
+
});
|
|
159
203
|
|
|
160
|
-
|
|
204
|
+
it("should round-trip compress and decompress v1", () => {
|
|
205
|
+
const original: FrakContextV1 = {
|
|
206
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
207
|
+
};
|
|
161
208
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
209
|
+
const compressed = FrakContextManager.compress(original);
|
|
210
|
+
const decompressed = FrakContextManager.decompress(compressed);
|
|
211
|
+
|
|
212
|
+
expect(decompressed).toEqual(original);
|
|
213
|
+
});
|
|
166
214
|
});
|
|
167
215
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
216
|
+
describe("parse", () => {
|
|
217
|
+
it("should parse URL with v1 fCtx parameter", () => {
|
|
218
|
+
const context: FrakContextV1 = {
|
|
219
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
220
|
+
};
|
|
221
|
+
const compressed = FrakContextManager.compress(context);
|
|
222
|
+
const url = `https://example.com?fCtx=${compressed}`;
|
|
171
223
|
|
|
172
|
-
|
|
224
|
+
const result = FrakContextManager.parse({ url });
|
|
173
225
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
226
|
+
expect(result).toBeDefined();
|
|
227
|
+
expect((result as FrakContextV1).r).toBe(
|
|
228
|
+
"0x1234567890123456789012345678901234567890"
|
|
229
|
+
);
|
|
230
|
+
});
|
|
178
231
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const url = "https://example.com";
|
|
182
|
-
const context: FrakContext = {
|
|
183
|
-
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
184
|
-
};
|
|
232
|
+
it("should return null for URL without fCtx parameter", () => {
|
|
233
|
+
const url = "https://example.com?other=param";
|
|
185
234
|
|
|
186
|
-
|
|
235
|
+
const result = FrakContextManager.parse({ url });
|
|
187
236
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
expect(result).toContain("https://example.com");
|
|
191
|
-
});
|
|
237
|
+
expect(result).toBeNull();
|
|
238
|
+
});
|
|
192
239
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
196
|
-
};
|
|
197
|
-
const compressed = FrakContextManager.compress(existingContext);
|
|
198
|
-
const url = `https://example.com?fCtx=${compressed}`;
|
|
240
|
+
it("should return null for empty URL", () => {
|
|
241
|
+
const result = FrakContextManager.parse({ url: "" });
|
|
199
242
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
};
|
|
243
|
+
expect(result).toBeNull();
|
|
244
|
+
});
|
|
203
245
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
246
|
+
it("should parse URL with multiple parameters", () => {
|
|
247
|
+
const context: FrakContextV1 = {
|
|
248
|
+
r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
|
|
249
|
+
};
|
|
250
|
+
const compressed = FrakContextManager.compress(context);
|
|
251
|
+
const url = `https://example.com?foo=bar&fCtx=${compressed}&baz=qux`;
|
|
252
|
+
|
|
253
|
+
const result = FrakContextManager.parse({ url });
|
|
254
|
+
|
|
255
|
+
expect(result).toBeDefined();
|
|
256
|
+
expect((result as FrakContextV1).r).toBe(
|
|
257
|
+
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
|
|
258
|
+
);
|
|
207
259
|
});
|
|
208
260
|
|
|
209
|
-
|
|
210
|
-
|
|
261
|
+
it("should return undefined for malformed fCtx parameter", () => {
|
|
262
|
+
const url = "https://example.com?fCtx=!!!invalid!!!";
|
|
211
263
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
);
|
|
264
|
+
const result = FrakContextManager.parse({ url });
|
|
265
|
+
|
|
266
|
+
expect(result).toBeUndefined();
|
|
267
|
+
});
|
|
217
268
|
});
|
|
218
269
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
270
|
+
describe("update", () => {
|
|
271
|
+
it("should add v1 fCtx to URL without existing context", () => {
|
|
272
|
+
const url = "https://example.com";
|
|
273
|
+
const context: FrakContextV1 = {
|
|
274
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
275
|
+
};
|
|
223
276
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
277
|
+
const result = FrakContextManager.update({ url, context });
|
|
278
|
+
|
|
279
|
+
expect(result).toBeDefined();
|
|
280
|
+
expect(result).toContain("fCtx=");
|
|
281
|
+
expect(result).toContain("https://example.com");
|
|
227
282
|
});
|
|
228
283
|
|
|
229
|
-
|
|
230
|
-
|
|
284
|
+
it("should return null when URL is undefined", () => {
|
|
285
|
+
const context: FrakContextV1 = {
|
|
286
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
287
|
+
};
|
|
231
288
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
289
|
+
const result = FrakContextManager.update({
|
|
290
|
+
url: undefined,
|
|
291
|
+
context,
|
|
292
|
+
});
|
|
235
293
|
|
|
236
|
-
|
|
294
|
+
expect(result).toBeNull();
|
|
295
|
+
});
|
|
237
296
|
|
|
238
|
-
|
|
239
|
-
|
|
297
|
+
it("should return null when context has no data", () => {
|
|
298
|
+
const url = "https://example.com";
|
|
299
|
+
// Runtime robustness: invalid object shape should return null.
|
|
300
|
+
const context = {} as any;
|
|
240
301
|
|
|
241
|
-
|
|
242
|
-
const url = "https://example.com?foo=bar&baz=qux";
|
|
243
|
-
const context: FrakContext = {
|
|
244
|
-
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
245
|
-
};
|
|
302
|
+
const result = FrakContextManager.update({ url, context });
|
|
246
303
|
|
|
247
|
-
|
|
304
|
+
expect(result).toBeNull();
|
|
305
|
+
});
|
|
248
306
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
307
|
+
it("should preserve other URL parameters", () => {
|
|
308
|
+
const url = "https://example.com?foo=bar&baz=qux";
|
|
309
|
+
const context: FrakContextV1 = {
|
|
310
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
311
|
+
};
|
|
253
312
|
|
|
254
|
-
|
|
255
|
-
const url = "https://example.com#section";
|
|
256
|
-
const context: FrakContext = {
|
|
257
|
-
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
258
|
-
};
|
|
313
|
+
const result = FrakContextManager.update({ url, context });
|
|
259
314
|
|
|
260
|
-
|
|
315
|
+
expect(result).toContain("foo=bar");
|
|
316
|
+
expect(result).toContain("baz=qux");
|
|
317
|
+
expect(result).toContain("fCtx=");
|
|
318
|
+
});
|
|
261
319
|
|
|
262
|
-
|
|
263
|
-
|
|
320
|
+
it("should preserve URL hash", () => {
|
|
321
|
+
const url = "https://example.com#section";
|
|
322
|
+
const context: FrakContextV1 = {
|
|
323
|
+
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const result = FrakContextManager.update({ url, context });
|
|
327
|
+
|
|
328
|
+
expect(result).toContain("#section");
|
|
329
|
+
expect(result).toContain("fCtx=");
|
|
330
|
+
});
|
|
264
331
|
});
|
|
265
332
|
});
|
|
266
333
|
|
|
267
334
|
describe("remove", () => {
|
|
268
335
|
it("should remove fCtx parameter from URL", () => {
|
|
269
|
-
const context:
|
|
336
|
+
const context: FrakContextV1 = {
|
|
270
337
|
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
271
338
|
};
|
|
272
339
|
const compressed = FrakContextManager.compress(context);
|
|
@@ -279,7 +346,7 @@ describe("FrakContextManager", () => {
|
|
|
279
346
|
});
|
|
280
347
|
|
|
281
348
|
it("should preserve other parameters when removing fCtx", () => {
|
|
282
|
-
const context:
|
|
349
|
+
const context: FrakContextV1 = {
|
|
283
350
|
r: "0x1234567890123456789012345678901234567890" as Address,
|
|
284
351
|
};
|
|
285
352
|
const compressed = FrakContextManager.compress(context);
|
|
@@ -316,7 +383,6 @@ describe("FrakContextManager", () => {
|
|
|
316
383
|
"0x1234567890123456789012345678901234567890" as Address;
|
|
317
384
|
|
|
318
385
|
beforeEach(() => {
|
|
319
|
-
// Mock window.location.href
|
|
320
386
|
Object.defineProperty(window, "location", {
|
|
321
387
|
writable: true,
|
|
322
388
|
value: {
|
|
@@ -324,13 +390,12 @@ describe("FrakContextManager", () => {
|
|
|
324
390
|
},
|
|
325
391
|
});
|
|
326
392
|
|
|
327
|
-
// Mock window.history using our test utility
|
|
328
393
|
mockWindowHistory(vi);
|
|
329
394
|
});
|
|
330
395
|
|
|
331
|
-
it("should update window.location with context", () => {
|
|
396
|
+
it("should update window.location with v1 context", () => {
|
|
332
397
|
const url = "https://example.com/test";
|
|
333
|
-
const context:
|
|
398
|
+
const context: FrakContextV1 = { r: mockAddress };
|
|
334
399
|
|
|
335
400
|
FrakContextManager.replaceUrl({ url, context });
|
|
336
401
|
|
|
@@ -347,9 +412,30 @@ describe("FrakContextManager", () => {
|
|
|
347
412
|
expect(calledUrl).toContain("fCtx=");
|
|
348
413
|
});
|
|
349
414
|
|
|
415
|
+
it("should update window.location with v2 context", () => {
|
|
416
|
+
const url = "https://example.com/test";
|
|
417
|
+
const context: FrakContextV2 = {
|
|
418
|
+
v: 2,
|
|
419
|
+
c: "client-id",
|
|
420
|
+
m: "merchant-id",
|
|
421
|
+
t: 1709654400,
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
FrakContextManager.replaceUrl({ url, context });
|
|
425
|
+
|
|
426
|
+
const historySpy = vi.mocked(window.history.replaceState);
|
|
427
|
+
expect(historySpy).toHaveBeenCalledTimes(1);
|
|
428
|
+
|
|
429
|
+
const calledUrl = historySpy.mock.calls[0]?.[2] as string;
|
|
430
|
+
expect(calledUrl).toContain("fCtx=");
|
|
431
|
+
|
|
432
|
+
const parsed = FrakContextManager.parse({ url: calledUrl });
|
|
433
|
+
expect(parsed).toEqual(context);
|
|
434
|
+
});
|
|
435
|
+
|
|
350
436
|
it("should use provided URL instead of window.location.href", () => {
|
|
351
437
|
const customUrl = "https://custom.com/path";
|
|
352
|
-
const context:
|
|
438
|
+
const context: FrakContextV1 = { r: mockAddress };
|
|
353
439
|
|
|
354
440
|
FrakContextManager.replaceUrl({ url: customUrl, context });
|
|
355
441
|
|
|
@@ -372,9 +458,9 @@ describe("FrakContextManager", () => {
|
|
|
372
458
|
expect(calledUrl).not.toContain("fCtx=");
|
|
373
459
|
});
|
|
374
460
|
|
|
375
|
-
it("should not call replaceState when context has no
|
|
461
|
+
it("should not call replaceState when context has no data", () => {
|
|
376
462
|
const url = "https://example.com/test";
|
|
377
|
-
const context
|
|
463
|
+
const context = {} as FrakContextV1;
|
|
378
464
|
|
|
379
465
|
FrakContextManager.replaceUrl({ url, context });
|
|
380
466
|
|
|
@@ -383,16 +469,14 @@ describe("FrakContextManager", () => {
|
|
|
383
469
|
});
|
|
384
470
|
|
|
385
471
|
it("should handle missing window gracefully", () => {
|
|
386
|
-
// Remove window.location to simulate missing window
|
|
387
472
|
Object.defineProperty(window, "location", {
|
|
388
473
|
writable: true,
|
|
389
474
|
value: undefined,
|
|
390
475
|
});
|
|
391
476
|
|
|
392
477
|
const url = "https://example.com/test";
|
|
393
|
-
const context:
|
|
478
|
+
const context: FrakContextV1 = { r: mockAddress };
|
|
394
479
|
|
|
395
|
-
// Should not throw error
|
|
396
480
|
expect(() => {
|
|
397
481
|
FrakContextManager.replaceUrl({ url, context });
|
|
398
482
|
}).not.toThrow();
|