@frak-labs/core-sdk 0.1.0-beta.8d103039 → 0.1.0-beta.d9302e66
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/package.json +20 -16
- package/src/actions/displayEmbeddedWallet.test.ts +194 -0
- package/src/actions/displayModal.test.ts +387 -0
- package/src/actions/getProductInformation.test.ts +133 -0
- package/src/actions/index.ts +19 -19
- package/src/actions/openSso.test.ts +407 -0
- package/src/actions/prepareSso.test.ts +223 -0
- package/src/actions/referral/processReferral.ts +1 -1
- package/src/actions/referral/referralInteraction.ts +1 -1
- package/src/actions/sendInteraction.test.ts +219 -0
- package/src/actions/trackPurchaseStatus.test.ts +287 -0
- package/src/actions/watchWalletStatus.test.ts +372 -0
- package/src/bundle.ts +1 -1
- package/src/clients/createIFrameFrakClient.ts +2 -2
- package/src/clients/index.ts +1 -1
- package/src/clients/setupClient.ts +3 -1
- package/src/clients/transports/iframeLifecycleManager.ts +3 -1
- package/src/index.ts +72 -74
- package/src/interactions/index.ts +2 -2
- package/src/interactions/pressEncoder.test.ts +215 -0
- package/src/interactions/pressEncoder.ts +1 -1
- package/src/interactions/purchaseEncoder.test.ts +291 -0
- package/src/interactions/purchaseEncoder.ts +8 -3
- package/src/interactions/referralEncoder.test.ts +170 -0
- package/src/interactions/retailEncoder.test.ts +107 -0
- package/src/interactions/retailEncoder.ts +1 -1
- package/src/interactions/webshopEncoder.test.ts +56 -0
- package/src/types/index.ts +51 -50
- package/src/types/lifecycle/index.ts +1 -1
- package/src/types/rpc/embedded/loggedIn.ts +1 -1
- package/src/types/rpc/embedded/loggedOut.ts +1 -1
- package/src/types/rpc/modal/index.ts +11 -11
- package/src/utils/FrakContext.test.ts +338 -0
- package/src/utils/FrakContext.ts +8 -2
- package/src/utils/compression/b64.test.ts +181 -0
- package/src/utils/compression/compress.test.ts +123 -0
- package/src/utils/compression/decompress.test.ts +145 -0
- package/src/utils/compression/index.ts +1 -1
- package/src/utils/computeProductId.test.ts +80 -0
- package/src/utils/constants.test.ts +23 -0
- package/src/utils/formatAmount.test.ts +113 -0
- package/src/utils/getCurrencyAmountKey.test.ts +44 -0
- package/src/utils/getSupportedCurrency.test.ts +51 -0
- package/src/utils/getSupportedLocale.test.ts +64 -0
- package/src/utils/iframeHelper.test.ts +450 -0
- package/src/utils/iframeHelper.ts +4 -3
- package/src/utils/index.ts +12 -12
- package/src/utils/sso.test.ts +361 -0
- package/src/utils/trackEvent.test.ts +162 -0
- package/cdn/bundle.js +0 -19
- package/cdn/bundle.js.LICENSE.txt +0 -10
- package/dist/actions.cjs +0 -1
- package/dist/actions.d.cts +0 -1481
- package/dist/actions.d.ts +0 -1481
- package/dist/actions.js +0 -1
- package/dist/bundle.cjs +0 -13
- package/dist/bundle.d.cts +0 -2087
- package/dist/bundle.d.ts +0 -2087
- package/dist/bundle.js +0 -13
- package/dist/index.cjs +0 -13
- package/dist/index.d.cts +0 -1387
- package/dist/index.d.ts +0 -1387
- package/dist/index.js +0 -13
- package/dist/interactions.cjs +0 -1
- package/dist/interactions.d.cts +0 -182
- package/dist/interactions.d.ts +0 -182
- package/dist/interactions.js +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for getCurrencyAmountKey utility function
|
|
3
|
+
* Tests currency amount key generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from "../../tests/vitest-fixtures";
|
|
7
|
+
import type { Currency } from "../types";
|
|
8
|
+
import { getCurrencyAmountKey } from "./getCurrencyAmountKey";
|
|
9
|
+
|
|
10
|
+
describe("getCurrencyAmountKey", () => {
|
|
11
|
+
it("should return eurAmount for undefined input", () => {
|
|
12
|
+
const result = getCurrencyAmountKey(undefined);
|
|
13
|
+
|
|
14
|
+
expect(result).toBe("eurAmount");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("should return eurAmount for EUR", () => {
|
|
18
|
+
const result = getCurrencyAmountKey("eur");
|
|
19
|
+
|
|
20
|
+
expect(result).toBe("eurAmount");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should return usdAmount for USD", () => {
|
|
24
|
+
const result = getCurrencyAmountKey("usd");
|
|
25
|
+
|
|
26
|
+
expect(result).toBe("usdAmount");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return gbpAmount for GBP", () => {
|
|
30
|
+
const result = getCurrencyAmountKey("gbp");
|
|
31
|
+
|
|
32
|
+
expect(result).toBe("gbpAmount");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should generate correct key format for all currencies", () => {
|
|
36
|
+
const validCurrencies: Currency[] = ["eur", "usd", "gbp"];
|
|
37
|
+
|
|
38
|
+
for (const currency of validCurrencies) {
|
|
39
|
+
const result = getCurrencyAmountKey(currency);
|
|
40
|
+
// Should match pattern: {currency}Amount
|
|
41
|
+
expect(result).toBe(`${currency}Amount`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for getSupportedCurrency utility function
|
|
3
|
+
* Tests currency validation and fallback behavior
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from "../../tests/vitest-fixtures";
|
|
7
|
+
import type { Currency } from "../types";
|
|
8
|
+
import { getSupportedCurrency } from "./getSupportedCurrency";
|
|
9
|
+
|
|
10
|
+
describe("getSupportedCurrency", () => {
|
|
11
|
+
it("should return EUR for undefined input", () => {
|
|
12
|
+
const result = getSupportedCurrency(undefined);
|
|
13
|
+
|
|
14
|
+
expect(result).toBe("eur");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("should return EUR when provided", () => {
|
|
18
|
+
const result = getSupportedCurrency("eur");
|
|
19
|
+
|
|
20
|
+
expect(result).toBe("eur");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should return USD when provided", () => {
|
|
24
|
+
const result = getSupportedCurrency("usd");
|
|
25
|
+
|
|
26
|
+
expect(result).toBe("usd");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return GBP when provided", () => {
|
|
30
|
+
const result = getSupportedCurrency("gbp");
|
|
31
|
+
|
|
32
|
+
expect(result).toBe("gbp");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should fall back to EUR for invalid currency", () => {
|
|
36
|
+
// Force cast to test runtime behavior
|
|
37
|
+
const invalidCurrency = "invalid" as Currency;
|
|
38
|
+
const result = getSupportedCurrency(invalidCurrency);
|
|
39
|
+
|
|
40
|
+
expect(result).toBe("eur");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should handle all valid currencies", () => {
|
|
44
|
+
const validCurrencies: Currency[] = ["eur", "usd", "gbp"];
|
|
45
|
+
|
|
46
|
+
for (const currency of validCurrencies) {
|
|
47
|
+
const result = getSupportedCurrency(currency);
|
|
48
|
+
expect(result).toBe(currency);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for getSupportedLocale utility function
|
|
3
|
+
* Tests locale resolution from currency
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from "../../tests/vitest-fixtures";
|
|
7
|
+
import { locales } from "../constants/locales";
|
|
8
|
+
import type { Currency } from "../types";
|
|
9
|
+
import { getSupportedLocale } from "./getSupportedLocale";
|
|
10
|
+
|
|
11
|
+
describe("getSupportedLocale", () => {
|
|
12
|
+
it("should return EUR locale for undefined input", () => {
|
|
13
|
+
const result = getSupportedLocale(undefined);
|
|
14
|
+
|
|
15
|
+
expect(result).toBe(locales.eur);
|
|
16
|
+
expect(result).toBe("fr-FR");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return French locale for EUR", () => {
|
|
20
|
+
const result = getSupportedLocale("eur");
|
|
21
|
+
|
|
22
|
+
expect(result).toBe(locales.eur);
|
|
23
|
+
expect(result).toBe("fr-FR");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should return US locale for USD", () => {
|
|
27
|
+
const result = getSupportedLocale("usd");
|
|
28
|
+
|
|
29
|
+
expect(result).toBe(locales.usd);
|
|
30
|
+
expect(result).toBe("en-US");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should return GB locale for GBP", () => {
|
|
34
|
+
const result = getSupportedLocale("gbp");
|
|
35
|
+
|
|
36
|
+
expect(result).toBe(locales.gbp);
|
|
37
|
+
expect(result).toBe("en-GB");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should fall back to EUR locale for invalid currency", () => {
|
|
41
|
+
// Force cast to test runtime behavior
|
|
42
|
+
const invalidCurrency = "invalid" as Currency;
|
|
43
|
+
const result = getSupportedLocale(invalidCurrency);
|
|
44
|
+
|
|
45
|
+
expect(result).toBe(locales.eur);
|
|
46
|
+
expect(result).toBe("fr-FR");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should return valid locale format", () => {
|
|
50
|
+
const validCurrencies: Currency[] = ["eur", "usd", "gbp"];
|
|
51
|
+
|
|
52
|
+
for (const currency of validCurrencies) {
|
|
53
|
+
const result = getSupportedLocale(currency);
|
|
54
|
+
// Should match locale format like "en-US", "fr-FR", etc.
|
|
55
|
+
expect(result).toMatch(/^[a-z]{2}-[A-Z]{2}$/);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should map all supported currencies to their locales", () => {
|
|
60
|
+
expect(getSupportedLocale("eur")).toBe("fr-FR");
|
|
61
|
+
expect(getSupportedLocale("usd")).toBe("en-US");
|
|
62
|
+
expect(getSupportedLocale("gbp")).toBe("en-GB");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for iframe helper utilities
|
|
3
|
+
* Tests iframe creation, visibility management, and finder functions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
afterEach,
|
|
8
|
+
beforeEach,
|
|
9
|
+
describe,
|
|
10
|
+
expect,
|
|
11
|
+
it,
|
|
12
|
+
vi,
|
|
13
|
+
} from "../../tests/vitest-fixtures";
|
|
14
|
+
import type { FrakWalletSdkConfig } from "../types";
|
|
15
|
+
import {
|
|
16
|
+
baseIframeProps,
|
|
17
|
+
changeIframeVisibility,
|
|
18
|
+
createIframe,
|
|
19
|
+
findIframeInOpener,
|
|
20
|
+
} from "./iframeHelper";
|
|
21
|
+
|
|
22
|
+
describe("iframeHelper", () => {
|
|
23
|
+
describe("baseIframeProps", () => {
|
|
24
|
+
it("should have correct id and name", () => {
|
|
25
|
+
expect(baseIframeProps.id).toBe("frak-wallet");
|
|
26
|
+
expect(baseIframeProps.name).toBe("frak-wallet");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should have correct title", () => {
|
|
30
|
+
expect(baseIframeProps.title).toBe("Frak Wallet");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should have correct allow attribute", () => {
|
|
34
|
+
expect(baseIframeProps.allow).toContain(
|
|
35
|
+
"publickey-credentials-get"
|
|
36
|
+
);
|
|
37
|
+
expect(baseIframeProps.allow).toContain("clipboard-write");
|
|
38
|
+
expect(baseIframeProps.allow).toContain("web-share");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should have correct initial style", () => {
|
|
42
|
+
expect(baseIframeProps.style.width).toBe("0");
|
|
43
|
+
expect(baseIframeProps.style.height).toBe("0");
|
|
44
|
+
expect(baseIframeProps.style.border).toBe("0");
|
|
45
|
+
expect(baseIframeProps.style.position).toBe("absolute");
|
|
46
|
+
expect(baseIframeProps.style.zIndex).toBe(2000001);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("createIframe", () => {
|
|
51
|
+
let mockIframe: HTMLIFrameElement;
|
|
52
|
+
let appendChildSpy: ReturnType<typeof vi.fn>;
|
|
53
|
+
let querySelectorSpy: ReturnType<typeof vi.fn>;
|
|
54
|
+
let createElementSpy: ReturnType<typeof vi.fn>;
|
|
55
|
+
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
// Create mock iframe
|
|
58
|
+
mockIframe = {
|
|
59
|
+
id: "",
|
|
60
|
+
name: "",
|
|
61
|
+
allow: "",
|
|
62
|
+
src: "",
|
|
63
|
+
style: {} as CSSStyleDeclaration,
|
|
64
|
+
addEventListener: vi.fn((event, handler) => {
|
|
65
|
+
if (event === "load") {
|
|
66
|
+
// Simulate immediate load
|
|
67
|
+
setTimeout(() => handler(), 0);
|
|
68
|
+
}
|
|
69
|
+
}),
|
|
70
|
+
remove: vi.fn(),
|
|
71
|
+
} as unknown as HTMLIFrameElement;
|
|
72
|
+
|
|
73
|
+
// Mock document methods
|
|
74
|
+
createElementSpy = vi
|
|
75
|
+
.spyOn(document, "createElement")
|
|
76
|
+
.mockReturnValue(mockIframe);
|
|
77
|
+
querySelectorSpy = vi
|
|
78
|
+
.spyOn(document, "querySelector")
|
|
79
|
+
.mockReturnValue(null);
|
|
80
|
+
appendChildSpy = vi
|
|
81
|
+
.spyOn(document.body, "appendChild")
|
|
82
|
+
.mockReturnValue(mockIframe);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
createElementSpy.mockRestore();
|
|
87
|
+
querySelectorSpy.mockRestore();
|
|
88
|
+
appendChildSpy.mockRestore();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should create iframe with correct properties", async () => {
|
|
92
|
+
await createIframe({});
|
|
93
|
+
|
|
94
|
+
expect(document.createElement).toHaveBeenCalledWith("iframe");
|
|
95
|
+
expect(mockIframe.id).toBe("frak-wallet");
|
|
96
|
+
expect(mockIframe.name).toBe("frak-wallet");
|
|
97
|
+
expect(mockIframe.allow).toContain("publickey-credentials-get");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should append iframe to document body", async () => {
|
|
101
|
+
await createIframe({});
|
|
102
|
+
|
|
103
|
+
expect(document.body.appendChild).toHaveBeenCalledWith(mockIframe);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should set iframe src to default wallet URL", async () => {
|
|
107
|
+
await createIframe({});
|
|
108
|
+
|
|
109
|
+
expect(mockIframe.src).toBe("https://wallet.frak.id/listener");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should use config walletUrl when provided", async () => {
|
|
113
|
+
const config: FrakWalletSdkConfig = {
|
|
114
|
+
walletUrl: "https://custom-wallet.com",
|
|
115
|
+
metadata: { name: "Test" },
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
await createIframe({ config });
|
|
119
|
+
|
|
120
|
+
expect(mockIframe.src).toBe("https://custom-wallet.com/listener");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should use deprecated walletBaseUrl when provided", async () => {
|
|
124
|
+
await createIframe({ walletBaseUrl: "https://legacy-wallet.com" });
|
|
125
|
+
|
|
126
|
+
expect(mockIframe.src).toBe("https://legacy-wallet.com/listener");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should prefer config.walletUrl over walletBaseUrl", async () => {
|
|
130
|
+
const config: FrakWalletSdkConfig = {
|
|
131
|
+
walletUrl: "https://new-wallet.com",
|
|
132
|
+
metadata: { name: "Test" },
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
await createIframe({
|
|
136
|
+
walletBaseUrl: "https://old-wallet.com",
|
|
137
|
+
config,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(mockIframe.src).toBe("https://new-wallet.com/listener");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should remove existing iframe before creating new one", async () => {
|
|
144
|
+
const existingIframe = {
|
|
145
|
+
remove: vi.fn(),
|
|
146
|
+
} as unknown as HTMLIFrameElement;
|
|
147
|
+
|
|
148
|
+
querySelectorSpy.mockReturnValue(existingIframe);
|
|
149
|
+
|
|
150
|
+
await createIframe({});
|
|
151
|
+
|
|
152
|
+
expect(document.querySelector).toHaveBeenCalledWith("#frak-wallet");
|
|
153
|
+
expect(existingIframe.remove).toHaveBeenCalled();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("should resolve promise on iframe load", async () => {
|
|
157
|
+
const result = await createIframe({});
|
|
158
|
+
|
|
159
|
+
expect(result).toBe(mockIframe);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should set iframe as initially hidden", async () => {
|
|
163
|
+
await createIframe({});
|
|
164
|
+
|
|
165
|
+
// Check that hidden styles were applied
|
|
166
|
+
expect(mockIframe.style.width).toBe("0");
|
|
167
|
+
expect(mockIframe.style.height).toBe("0");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should set zIndex from baseIframeProps", async () => {
|
|
171
|
+
await createIframe({});
|
|
172
|
+
|
|
173
|
+
expect(mockIframe.style.zIndex).toBe("2000001");
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("changeIframeVisibility", () => {
|
|
178
|
+
let mockIframe: HTMLIFrameElement;
|
|
179
|
+
|
|
180
|
+
beforeEach(() => {
|
|
181
|
+
mockIframe = {
|
|
182
|
+
style: {} as CSSStyleDeclaration,
|
|
183
|
+
} as HTMLIFrameElement;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("when hiding iframe (isVisible: false)", () => {
|
|
187
|
+
it("should set width and height to 0", () => {
|
|
188
|
+
changeIframeVisibility({
|
|
189
|
+
iframe: mockIframe,
|
|
190
|
+
isVisible: false,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(mockIframe.style.width).toBe("0");
|
|
194
|
+
expect(mockIframe.style.height).toBe("0");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should set border to 0", () => {
|
|
198
|
+
changeIframeVisibility({
|
|
199
|
+
iframe: mockIframe,
|
|
200
|
+
isVisible: false,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
expect(mockIframe.style.border).toBe("0");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("should set position to fixed", () => {
|
|
207
|
+
changeIframeVisibility({
|
|
208
|
+
iframe: mockIframe,
|
|
209
|
+
isVisible: false,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(mockIframe.style.position).toBe("fixed");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("should move iframe off-screen", () => {
|
|
216
|
+
changeIframeVisibility({
|
|
217
|
+
iframe: mockIframe,
|
|
218
|
+
isVisible: false,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(mockIframe.style.top).toBe("-1000px");
|
|
222
|
+
expect(mockIframe.style.left).toBe("-1000px");
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe("when showing iframe (isVisible: true)", () => {
|
|
227
|
+
it("should set full screen dimensions", () => {
|
|
228
|
+
changeIframeVisibility({ iframe: mockIframe, isVisible: true });
|
|
229
|
+
|
|
230
|
+
expect(mockIframe.style.width).toBe("100%");
|
|
231
|
+
expect(mockIframe.style.height).toBe("100%");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("should position at top-left", () => {
|
|
235
|
+
changeIframeVisibility({ iframe: mockIframe, isVisible: true });
|
|
236
|
+
|
|
237
|
+
expect(mockIframe.style.top).toBe("0");
|
|
238
|
+
expect(mockIframe.style.left).toBe("0");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should set position to fixed", () => {
|
|
242
|
+
changeIframeVisibility({ iframe: mockIframe, isVisible: true });
|
|
243
|
+
|
|
244
|
+
expect(mockIframe.style.position).toBe("fixed");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should enable pointer events", () => {
|
|
248
|
+
changeIframeVisibility({ iframe: mockIframe, isVisible: true });
|
|
249
|
+
|
|
250
|
+
expect(mockIframe.style.pointerEvents).toBe("auto");
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe("toggling visibility", () => {
|
|
255
|
+
it("should hide then show correctly", () => {
|
|
256
|
+
changeIframeVisibility({ iframe: mockIframe, isVisible: true });
|
|
257
|
+
expect(mockIframe.style.width).toBe("100%");
|
|
258
|
+
|
|
259
|
+
changeIframeVisibility({
|
|
260
|
+
iframe: mockIframe,
|
|
261
|
+
isVisible: false,
|
|
262
|
+
});
|
|
263
|
+
expect(mockIframe.style.width).toBe("0");
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("should show then hide correctly", () => {
|
|
267
|
+
changeIframeVisibility({
|
|
268
|
+
iframe: mockIframe,
|
|
269
|
+
isVisible: false,
|
|
270
|
+
});
|
|
271
|
+
expect(mockIframe.style.top).toBe("-1000px");
|
|
272
|
+
|
|
273
|
+
changeIframeVisibility({ iframe: mockIframe, isVisible: true });
|
|
274
|
+
expect(mockIframe.style.top).toBe("0");
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("findIframeInOpener", () => {
|
|
280
|
+
let originalOpener: Window;
|
|
281
|
+
let consoleErrorSpy: any;
|
|
282
|
+
|
|
283
|
+
beforeEach(() => {
|
|
284
|
+
originalOpener = window.opener;
|
|
285
|
+
consoleErrorSpy = vi
|
|
286
|
+
.spyOn(console, "error")
|
|
287
|
+
.mockImplementation(() => {});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
afterEach(() => {
|
|
291
|
+
window.opener = originalOpener;
|
|
292
|
+
consoleErrorSpy.mockRestore();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("should return null when window.opener is not available", () => {
|
|
296
|
+
window.opener = null;
|
|
297
|
+
|
|
298
|
+
const result = findIframeInOpener();
|
|
299
|
+
|
|
300
|
+
expect(result).toBeNull();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("should find iframe in window.opener with default pathname", () => {
|
|
304
|
+
const mockOpener = {
|
|
305
|
+
location: {
|
|
306
|
+
origin: window.location.origin,
|
|
307
|
+
pathname: "/listener",
|
|
308
|
+
},
|
|
309
|
+
frames: [],
|
|
310
|
+
} as unknown as Window;
|
|
311
|
+
|
|
312
|
+
window.opener = mockOpener;
|
|
313
|
+
|
|
314
|
+
const result = findIframeInOpener();
|
|
315
|
+
|
|
316
|
+
expect(result).toBe(mockOpener);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("should find iframe with custom pathname", () => {
|
|
320
|
+
const mockOpener = {
|
|
321
|
+
location: {
|
|
322
|
+
origin: window.location.origin,
|
|
323
|
+
pathname: "/custom-iframe",
|
|
324
|
+
},
|
|
325
|
+
frames: [],
|
|
326
|
+
} as unknown as Window;
|
|
327
|
+
|
|
328
|
+
window.opener = mockOpener;
|
|
329
|
+
|
|
330
|
+
const result = findIframeInOpener("/custom-iframe");
|
|
331
|
+
|
|
332
|
+
expect(result).toBe(mockOpener);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("should search through frames in window.opener", () => {
|
|
336
|
+
const matchingFrame = {
|
|
337
|
+
location: {
|
|
338
|
+
origin: window.location.origin,
|
|
339
|
+
pathname: "/listener",
|
|
340
|
+
},
|
|
341
|
+
} as unknown as Window;
|
|
342
|
+
|
|
343
|
+
const nonMatchingFrame = {
|
|
344
|
+
location: {
|
|
345
|
+
origin: window.location.origin,
|
|
346
|
+
pathname: "/other",
|
|
347
|
+
},
|
|
348
|
+
} as unknown as Window;
|
|
349
|
+
|
|
350
|
+
const mockOpener = {
|
|
351
|
+
location: {
|
|
352
|
+
origin: window.location.origin,
|
|
353
|
+
pathname: "/parent",
|
|
354
|
+
},
|
|
355
|
+
frames: [nonMatchingFrame, matchingFrame],
|
|
356
|
+
length: 2,
|
|
357
|
+
} as unknown as Window;
|
|
358
|
+
|
|
359
|
+
window.opener = mockOpener;
|
|
360
|
+
|
|
361
|
+
const result = findIframeInOpener();
|
|
362
|
+
|
|
363
|
+
expect(result).toBe(matchingFrame);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("should return null when no matching frame is found", () => {
|
|
367
|
+
const mockOpener = {
|
|
368
|
+
location: {
|
|
369
|
+
origin: window.location.origin,
|
|
370
|
+
pathname: "/wrong",
|
|
371
|
+
},
|
|
372
|
+
frames: [],
|
|
373
|
+
} as unknown as Window;
|
|
374
|
+
|
|
375
|
+
window.opener = mockOpener;
|
|
376
|
+
|
|
377
|
+
const result = findIframeInOpener("/listener");
|
|
378
|
+
|
|
379
|
+
expect(result).toBeNull();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it("should handle cross-origin frames gracefully", () => {
|
|
383
|
+
const crossOriginFrame = {
|
|
384
|
+
get location() {
|
|
385
|
+
throw new Error(
|
|
386
|
+
"SecurityError: Blocked a frame with origin"
|
|
387
|
+
);
|
|
388
|
+
},
|
|
389
|
+
} as unknown as Window;
|
|
390
|
+
|
|
391
|
+
const mockOpener = {
|
|
392
|
+
location: {
|
|
393
|
+
origin: window.location.origin,
|
|
394
|
+
pathname: "/parent",
|
|
395
|
+
},
|
|
396
|
+
frames: [crossOriginFrame],
|
|
397
|
+
length: 1,
|
|
398
|
+
} as unknown as Window;
|
|
399
|
+
|
|
400
|
+
window.opener = mockOpener;
|
|
401
|
+
|
|
402
|
+
const result = findIframeInOpener();
|
|
403
|
+
|
|
404
|
+
expect(result).toBeNull();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("should handle errors during frame search", () => {
|
|
408
|
+
const mockOpener = {
|
|
409
|
+
location: {
|
|
410
|
+
origin: window.location.origin,
|
|
411
|
+
pathname: "/parent",
|
|
412
|
+
},
|
|
413
|
+
get frames() {
|
|
414
|
+
throw new Error("Access denied");
|
|
415
|
+
},
|
|
416
|
+
} as unknown as Window;
|
|
417
|
+
|
|
418
|
+
window.opener = mockOpener;
|
|
419
|
+
|
|
420
|
+
const result = findIframeInOpener();
|
|
421
|
+
|
|
422
|
+
expect(result).toBeNull();
|
|
423
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it("should match origin correctly", () => {
|
|
427
|
+
const wrongOriginFrame = {
|
|
428
|
+
location: {
|
|
429
|
+
origin: "https://different-origin.com",
|
|
430
|
+
pathname: "/listener",
|
|
431
|
+
},
|
|
432
|
+
} as unknown as Window;
|
|
433
|
+
|
|
434
|
+
const mockOpener = {
|
|
435
|
+
location: {
|
|
436
|
+
origin: "https://different-origin.com",
|
|
437
|
+
pathname: "/parent",
|
|
438
|
+
},
|
|
439
|
+
frames: [wrongOriginFrame],
|
|
440
|
+
length: 1,
|
|
441
|
+
} as unknown as Window;
|
|
442
|
+
|
|
443
|
+
window.opener = mockOpener;
|
|
444
|
+
|
|
445
|
+
const result = findIframeInOpener();
|
|
446
|
+
|
|
447
|
+
expect(result).toBeNull();
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
});
|
|
@@ -30,9 +30,10 @@ export const baseIframeProps = {
|
|
|
30
30
|
export function createIframe({
|
|
31
31
|
walletBaseUrl,
|
|
32
32
|
config,
|
|
33
|
-
}: {
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
}: {
|
|
34
|
+
walletBaseUrl?: string;
|
|
35
|
+
config?: FrakWalletSdkConfig;
|
|
36
|
+
}): Promise<HTMLIFrameElement | undefined> {
|
|
36
37
|
// Check if the iframe is already created
|
|
37
38
|
const alreadyCreatedIFrame = document.querySelector("#frak-wallet");
|
|
38
39
|
|
package/src/utils/index.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
3
|
-
baseIframeProps,
|
|
4
|
-
findIframeInOpener,
|
|
5
|
-
} from "./iframeHelper";
|
|
1
|
+
export { Deferred } from "@frak-labs/frame-connector";
|
|
2
|
+
export { base64urlDecode, base64urlEncode } from "./compression/b64";
|
|
6
3
|
export { compressJsonToB64 } from "./compression/compress";
|
|
7
4
|
export { decompressJsonFromB64 } from "./compression/decompress";
|
|
8
|
-
export { base64urlDecode, base64urlEncode } from "./compression/b64";
|
|
9
5
|
export { FrakContextManager } from "./FrakContext";
|
|
6
|
+
export { formatAmount } from "./formatAmount";
|
|
7
|
+
export { getCurrencyAmountKey } from "./getCurrencyAmountKey";
|
|
10
8
|
export { getSupportedCurrency } from "./getSupportedCurrency";
|
|
11
9
|
export { getSupportedLocale } from "./getSupportedLocale";
|
|
12
|
-
export { getCurrencyAmountKey } from "./getCurrencyAmountKey";
|
|
13
|
-
export { formatAmount } from "./formatAmount";
|
|
14
|
-
export { trackEvent } from "./trackEvent";
|
|
15
|
-
export { Deferred } from "@frak-labs/frame-connector";
|
|
16
10
|
export {
|
|
17
|
-
|
|
11
|
+
baseIframeProps,
|
|
12
|
+
createIframe,
|
|
13
|
+
findIframeInOpener,
|
|
14
|
+
} from "./iframeHelper";
|
|
15
|
+
export {
|
|
16
|
+
type AppSpecificSsoMetadata,
|
|
18
17
|
type CompressedSsoData,
|
|
19
18
|
type FullSsoParams,
|
|
20
|
-
|
|
19
|
+
generateSsoUrl,
|
|
21
20
|
} from "./sso";
|
|
21
|
+
export { trackEvent } from "./trackEvent";
|