@notabene/javascript-sdk 2.1.0 → 2.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/README.md +24 -0
- package/dist/notabene.cjs +1 -1
- package/dist/notabene.d.ts +10 -3
- package/dist/notabene.js +101 -70
- package/docs/README.md +24 -0
- package/docs/_media/TransactionOptions.md +6 -6
- package/docs/ivms/types/enumerations/PayloadVersionCode.md +2 -2
- package/docs/ivms/types/interfaces/PayloadMetadata.md +2 -2
- package/docs/ivms/types/type-aliases/Address.md +1 -1
- package/docs/ivms/types/type-aliases/AddressTypeCode.md +1 -1
- package/docs/ivms/types/type-aliases/Beneficiary.md +1 -1
- package/docs/ivms/types/type-aliases/BeneficiaryVASP.md +1 -1
- package/docs/ivms/types/type-aliases/DateAndPlaceOfBirth.md +1 -1
- package/docs/ivms/types/type-aliases/ISOCountryCode.md +1 -1
- package/docs/ivms/types/type-aliases/ISODate.md +1 -1
- package/docs/ivms/types/type-aliases/IVMS101.md +1 -1
- package/docs/ivms/types/type-aliases/IntermediaryVASP.md +1 -1
- package/docs/ivms/types/type-aliases/LegalPerson.md +1 -1
- package/docs/ivms/types/type-aliases/LegalPersonName.md +1 -1
- package/docs/ivms/types/type-aliases/LegalPersonNameID.md +1 -1
- package/docs/ivms/types/type-aliases/LegalPersonNameTypeCode.md +1 -1
- package/docs/ivms/types/type-aliases/LocalLegalPersonNameID.md +1 -1
- package/docs/ivms/types/type-aliases/LocalNaturalPersonNameID.md +1 -1
- package/docs/ivms/types/type-aliases/NationalIdentification.md +1 -1
- package/docs/ivms/types/type-aliases/NationalIdentifierTypeCode.md +1 -1
- package/docs/ivms/types/type-aliases/NaturalPerson.md +1 -1
- package/docs/ivms/types/type-aliases/NaturalPersonName.md +1 -1
- package/docs/ivms/types/type-aliases/NaturalPersonNameID.md +1 -1
- package/docs/ivms/types/type-aliases/NaturalPersonNameTypeCode.md +1 -1
- package/docs/ivms/types/type-aliases/OriginatingVASP.md +1 -1
- package/docs/ivms/types/type-aliases/Originator.md +1 -1
- package/docs/ivms/types/type-aliases/Person.md +1 -1
- package/docs/ivms/types/type-aliases/TransferPath.md +1 -1
- package/docs/ivms/types/type-aliases/TransliterationMethodCode.md +1 -1
- package/docs/notabene/classes/EmbeddedComponent.md +39 -16
- package/docs/notabene/classes/default.md +6 -6
- package/docs/notabene/functions/decodeFragmentToObject.md +1 -1
- package/docs/notabene/interfaces/NotabeneConfig.md +5 -5
- package/docs/notabene/type-aliases/MessageCallback.md +1 -1
- package/docs/types/enumerations/AgentType.md +2 -2
- package/docs/types/enumerations/CMType.md +6 -6
- package/docs/types/enumerations/HMType.md +2 -2
- package/docs/types/enumerations/PersonType.md +3 -3
- package/docs/types/enumerations/ProofStatus.md +4 -4
- package/docs/types/enumerations/ProofTypes.md +12 -12
- package/docs/types/enumerations/Status.md +5 -5
- package/docs/types/enumerations/VASPSearchControl.md +2 -2
- package/docs/types/enumerations/ValidationSections.md +4 -4
- package/docs/types/interfaces/Agent.md +6 -6
- package/docs/types/interfaces/CallbackOptions.md +2 -2
- package/docs/types/interfaces/ComponentRequest.md +2 -2
- package/docs/types/interfaces/ComponentResponse.md +4 -4
- package/docs/types/interfaces/ConnectionRecord.md +7 -7
- package/docs/types/interfaces/ConnectionRequest.md +3 -3
- package/docs/types/interfaces/Counterparty.md +10 -10
- package/docs/types/interfaces/DeclarationProof.md +6 -6
- package/docs/types/interfaces/Deposit.md +9 -9
- package/docs/types/interfaces/DepositRequest.md +7 -7
- package/docs/types/interfaces/DepositRequestOptions.md +1 -1
- package/docs/types/interfaces/LegalPerson.md +13 -13
- package/docs/types/interfaces/MicroTransferProof.md +9 -9
- package/docs/types/interfaces/NaturalPerson.md +13 -13
- package/docs/types/interfaces/OwnershipProof.md +4 -4
- package/docs/types/interfaces/ScreenshotProof.md +5 -5
- package/docs/types/interfaces/SignatureProof.md +7 -7
- package/docs/types/interfaces/ThresholdOptions.md +3 -3
- package/docs/types/interfaces/Transaction.md +8 -8
- package/docs/types/interfaces/TransactionOptions.md +6 -6
- package/docs/types/interfaces/TransactionResponse.md +8 -8
- package/docs/types/interfaces/VASP.md +9 -9
- package/docs/types/interfaces/Wallet.md +8 -8
- package/docs/types/interfaces/Withdrawal.md +9 -9
- package/docs/types/type-aliases/BlockchainAddress.md +1 -1
- package/docs/types/type-aliases/CAIP10.md +1 -1
- package/docs/types/type-aliases/CAIP19.md +1 -1
- package/docs/types/type-aliases/CAIP2.md +1 -1
- package/docs/types/type-aliases/CAIP220.md +1 -1
- package/docs/types/type-aliases/Cancel.md +1 -1
- package/docs/types/type-aliases/Completed.md +1 -1
- package/docs/types/type-aliases/ComponentMessage.md +1 -1
- package/docs/types/type-aliases/ConnectionOptions.md +1 -1
- package/docs/types/type-aliases/CryptoCredential.md +1 -1
- package/docs/types/type-aliases/DID.md +1 -1
- package/docs/types/type-aliases/DTI.md +1 -1
- package/docs/types/type-aliases/Destination.md +1 -1
- package/docs/types/type-aliases/Error.md +1 -1
- package/docs/types/type-aliases/FieldOptions.md +1 -1
- package/docs/types/type-aliases/FieldTypes.md +1 -1
- package/docs/types/type-aliases/HostMessage.md +1 -1
- package/docs/types/type-aliases/ISOCurrency.md +1 -1
- package/docs/types/type-aliases/InvalidValue.md +1 -1
- package/docs/types/type-aliases/LEI.md +1 -1
- package/docs/types/type-aliases/LegalPersonFieldName.md +1 -1
- package/docs/types/type-aliases/LegalPersonFields.md +1 -1
- package/docs/types/type-aliases/NaturalPersonFieldName.md +1 -1
- package/docs/types/type-aliases/NaturalPersonFields.md +1 -1
- package/docs/types/type-aliases/NotabeneAsset.md +1 -1
- package/docs/types/type-aliases/ResizeRequest.md +1 -1
- package/docs/types/type-aliases/Source.md +1 -1
- package/docs/types/type-aliases/Theme.md +1 -1
- package/docs/types/type-aliases/TransactionAsset.md +1 -1
- package/docs/types/type-aliases/TravelAddress.md +1 -1
- package/docs/types/type-aliases/URI.md +1 -1
- package/docs/types/type-aliases/UUID.md +1 -1
- package/docs/types/type-aliases/UpdateValue.md +1 -1
- package/docs/types/type-aliases/V1Asset.md +1 -1
- package/docs/types/type-aliases/V1Transaction.md +1 -1
- package/docs/types/type-aliases/VASPOptions.md +1 -1
- package/docs/types/type-aliases/ValidationError.md +1 -1
- package/package.json +7 -5
- package/src/components/EmbeddedComponent.ts +49 -5
- package/src/types.ts +3 -3
- package/src/components/__tests__/EmbeddedComponent.test.ts +0 -530
|
@@ -102,7 +102,7 @@ export default class EmbeddedComponent<V, O> {
|
|
|
102
102
|
this.removeEmbed();
|
|
103
103
|
this.iframe = document.createElement('iframe');
|
|
104
104
|
this.iframe.src = this.url + (!modal ? '&embedded=true' : '');
|
|
105
|
-
this.iframe.allow = 'web-share; clipboard-write';
|
|
105
|
+
this.iframe.allow = 'web-share; clipboard-write; hid; bluetooth;';
|
|
106
106
|
this.iframe.style.width = '100%';
|
|
107
107
|
this.iframe.style.height = '0px';
|
|
108
108
|
this.iframe.style.border = 'none';
|
|
@@ -173,15 +173,21 @@ export default class EmbeddedComponent<V, O> {
|
|
|
173
173
|
completion(): Promise<TransactionResponse<V>> {
|
|
174
174
|
return new Promise((resolve, reject) => {
|
|
175
175
|
let removeComplete: undefined | (() => void) = undefined;
|
|
176
|
+
let removeCancel: undefined | (() => void) = undefined;
|
|
176
177
|
let removeError: undefined | (() => void) = undefined;
|
|
177
178
|
function cleanup() {
|
|
178
179
|
if (removeComplete) removeComplete();
|
|
180
|
+
if (removeCancel) removeCancel();
|
|
179
181
|
if (removeError) removeError();
|
|
180
182
|
}
|
|
181
183
|
removeComplete = this.on(CMType.COMPLETE, (message) => {
|
|
182
184
|
resolve((message as any).response);
|
|
183
185
|
cleanup();
|
|
184
186
|
});
|
|
187
|
+
removeCancel = this.on(CMType.CANCEL, () => {
|
|
188
|
+
reject(new Error('User cancelled'));
|
|
189
|
+
cleanup();
|
|
190
|
+
});
|
|
185
191
|
removeError = this.on('error', (message) => {
|
|
186
192
|
reject(new Error((message as any).message));
|
|
187
193
|
cleanup();
|
|
@@ -193,7 +199,7 @@ export default class EmbeddedComponent<V, O> {
|
|
|
193
199
|
* Opens the component in a modal dialog
|
|
194
200
|
*/
|
|
195
201
|
|
|
196
|
-
openModal(): Promise<TransactionResponse<V>> {
|
|
202
|
+
async openModal(): Promise<TransactionResponse<V>> {
|
|
197
203
|
if (this.modal) {
|
|
198
204
|
this.closeModal();
|
|
199
205
|
}
|
|
@@ -207,11 +213,11 @@ export default class EmbeddedComponent<V, O> {
|
|
|
207
213
|
|
|
208
214
|
document.body.appendChild(this.modal);
|
|
209
215
|
this.embed(this.modal, true);
|
|
210
|
-
this.on(CMType.CANCEL, () => {
|
|
216
|
+
const removeCancel = this.on(CMType.CANCEL, () => {
|
|
211
217
|
this.closeModal();
|
|
212
218
|
});
|
|
213
219
|
|
|
214
|
-
this.on(CMType.COMPLETE, () => {
|
|
220
|
+
const removeComplete = this.on(CMType.COMPLETE, () => {
|
|
215
221
|
this.closeModal();
|
|
216
222
|
});
|
|
217
223
|
|
|
@@ -220,8 +226,12 @@ export default class EmbeddedComponent<V, O> {
|
|
|
220
226
|
// console.log('click');
|
|
221
227
|
this.closeModal();
|
|
222
228
|
});
|
|
223
|
-
return this.completion()
|
|
229
|
+
return this.completion().finally(() => {
|
|
230
|
+
removeCancel();
|
|
231
|
+
removeComplete();
|
|
232
|
+
});
|
|
224
233
|
}
|
|
234
|
+
|
|
225
235
|
/**
|
|
226
236
|
* Closes the modal dialog
|
|
227
237
|
*
|
|
@@ -235,4 +245,38 @@ export default class EmbeddedComponent<V, O> {
|
|
|
235
245
|
this.modal = undefined;
|
|
236
246
|
}
|
|
237
247
|
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Opens the component in a popup window. This may be needed to support many self-hosted wallets
|
|
251
|
+
* @returns A promise that resolves with the transaction response
|
|
252
|
+
* @see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#restrictions)
|
|
253
|
+
* @see [Cross-Origin-Opener-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy)
|
|
254
|
+
*/
|
|
255
|
+
async popup(): Promise<TransactionResponse<V>> {
|
|
256
|
+
const popup = window.open(
|
|
257
|
+
this.url,
|
|
258
|
+
'_blank',
|
|
259
|
+
'popup=true,width=600,height=600',
|
|
260
|
+
);
|
|
261
|
+
window.addEventListener('message', (event: MessageEvent) => {
|
|
262
|
+
if (event.source !== popup) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
console.log('received message from popup', event.data);
|
|
266
|
+
this.eventManager?.setPort(event.ports[0]);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const removeCancel = this.on(CMType.CANCEL, () => {
|
|
270
|
+
popup?.close();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const removeComplete = this.on(CMType.COMPLETE, () => {
|
|
274
|
+
popup?.close();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return this.completion().finally(() => {
|
|
278
|
+
removeCancel();
|
|
279
|
+
removeComplete();
|
|
280
|
+
});
|
|
281
|
+
}
|
|
238
282
|
}
|
package/src/types.ts
CHANGED
|
@@ -708,7 +708,7 @@ export type FieldTypes = {
|
|
|
708
708
|
* - PENDING: Include VASPs neither allowed nor denied
|
|
709
709
|
* @public
|
|
710
710
|
*/
|
|
711
|
-
export
|
|
711
|
+
export enum VASPSearchControl {
|
|
712
712
|
ALLOWED = 'allowed',
|
|
713
713
|
PENDING = 'pending',
|
|
714
714
|
}
|
|
@@ -784,7 +784,7 @@ export interface TransactionOptions {
|
|
|
784
784
|
* - CANCEL: Operation was cancelled
|
|
785
785
|
* @public
|
|
786
786
|
*/
|
|
787
|
-
export
|
|
787
|
+
export enum CMType {
|
|
788
788
|
COMPLETE = 'complete',
|
|
789
789
|
RESIZE = 'resize',
|
|
790
790
|
RESULT = 'result',
|
|
@@ -885,7 +885,7 @@ export type ComponentMessage<T> =
|
|
|
885
885
|
* - REQUEST_RESPONSE: Message requesting a response from component
|
|
886
886
|
* @public
|
|
887
887
|
*/
|
|
888
|
-
export
|
|
888
|
+
export enum HMType {
|
|
889
889
|
UPDATE = 'update',
|
|
890
890
|
REQUEST_RESPONSE = 'requestResponse',
|
|
891
891
|
}
|
|
@@ -1,530 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
AgentType,
|
|
4
|
-
CMType,
|
|
5
|
-
HMType,
|
|
6
|
-
type HostMessage,
|
|
7
|
-
type Transaction,
|
|
8
|
-
type TransactionOptions,
|
|
9
|
-
type Withdrawal,
|
|
10
|
-
} from '../../types';
|
|
11
|
-
import { MessageEventManager } from '../../utils/MessageEventManager';
|
|
12
|
-
import EmbeddedComponent from '../EmbeddedComponent';
|
|
13
|
-
|
|
14
|
-
const url = 'https://example.com';
|
|
15
|
-
const parentId = 'parent-container';
|
|
16
|
-
const value: Partial<Transaction> = { amountDecimal: 100 };
|
|
17
|
-
|
|
18
|
-
describe('EmbeddedComponent', () => {
|
|
19
|
-
describe('creation', () => {
|
|
20
|
-
let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
component = new EmbeddedComponent<Withdrawal, TransactionOptions>(url, {
|
|
23
|
-
amountDecimal: 100,
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('sets value', () => {
|
|
28
|
-
expect(component.value).toStrictEqual(value);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('sets url', () => {
|
|
32
|
-
expect(component.url).toBe(url);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('iframe', () => {
|
|
37
|
-
let document: Document;
|
|
38
|
-
let parentElement: HTMLElement;
|
|
39
|
-
let iframe: HTMLIFrameElement;
|
|
40
|
-
let window: Window;
|
|
41
|
-
|
|
42
|
-
beforeEach(() => {
|
|
43
|
-
parentElement = {
|
|
44
|
-
appendChild: vi.fn(),
|
|
45
|
-
} as unknown as HTMLElement;
|
|
46
|
-
|
|
47
|
-
iframe = {
|
|
48
|
-
style: {},
|
|
49
|
-
src: '',
|
|
50
|
-
contentWindow: {
|
|
51
|
-
focus: vi.fn(),
|
|
52
|
-
} as unknown as Window,
|
|
53
|
-
remove: vi.fn(),
|
|
54
|
-
setAttribute: vi.fn(),
|
|
55
|
-
addEventListener: vi.fn(),
|
|
56
|
-
} as unknown as HTMLIFrameElement;
|
|
57
|
-
|
|
58
|
-
document = {
|
|
59
|
-
createElement: vi.fn().mockReturnValue(iframe),
|
|
60
|
-
querySelector: vi.fn().mockReturnValue(parentElement),
|
|
61
|
-
} as unknown as Document;
|
|
62
|
-
|
|
63
|
-
window = {
|
|
64
|
-
addEventListener: vi.fn(),
|
|
65
|
-
} as unknown as Window;
|
|
66
|
-
|
|
67
|
-
vi.stubGlobal('document', document);
|
|
68
|
-
vi.stubGlobal('window', window);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
afterEach(() => {
|
|
72
|
-
vi.unstubAllGlobals();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('mount', () => {
|
|
76
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
77
|
-
url,
|
|
78
|
-
value,
|
|
79
|
-
);
|
|
80
|
-
component.mount(parentId);
|
|
81
|
-
expect(iframe?.src).toBe(url + '&embedded=true');
|
|
82
|
-
expect(parentElement.appendChild).toHaveBeenCalledWith(iframe);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('on', () => {
|
|
86
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
87
|
-
url,
|
|
88
|
-
value,
|
|
89
|
-
);
|
|
90
|
-
const messageType = 'customEvent';
|
|
91
|
-
const callback = vi.fn();
|
|
92
|
-
component.on(messageType, callback);
|
|
93
|
-
component.mount(parentId);
|
|
94
|
-
|
|
95
|
-
// Simulate receiving a message of the specified type
|
|
96
|
-
// and assert that the callback is called with the correct payload.
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('off', () => {
|
|
100
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
101
|
-
url,
|
|
102
|
-
value,
|
|
103
|
-
);
|
|
104
|
-
const messageType = 'customEvent';
|
|
105
|
-
const callback = vi.fn();
|
|
106
|
-
component.on(messageType, callback);
|
|
107
|
-
|
|
108
|
-
// Simulate receiving a message of the specified type
|
|
109
|
-
// and assert that the callback is called with the correct payload.
|
|
110
|
-
|
|
111
|
-
component.off(messageType, callback);
|
|
112
|
-
|
|
113
|
-
// Simulate receiving another message of the specified type
|
|
114
|
-
// and assert that the callback is not called.
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe('connected to iframe', () => {
|
|
118
|
-
let messageHandler: (event: MessageEvent) => void;
|
|
119
|
-
let port: MessagePort;
|
|
120
|
-
let handshake: MessageEvent;
|
|
121
|
-
let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
|
|
122
|
-
let options: TransactionOptions;
|
|
123
|
-
|
|
124
|
-
beforeEach(() => {
|
|
125
|
-
port = {
|
|
126
|
-
postMessage: vi.fn(),
|
|
127
|
-
start: vi.fn(),
|
|
128
|
-
onmessage: null,
|
|
129
|
-
} as unknown as MessagePort;
|
|
130
|
-
handshake = {
|
|
131
|
-
source: iframe.contentWindow,
|
|
132
|
-
ports: [port],
|
|
133
|
-
} as unknown as MessageEvent;
|
|
134
|
-
window.addEventListener = vi
|
|
135
|
-
.fn()
|
|
136
|
-
.mockImplementation((event, handler) => {
|
|
137
|
-
messageHandler = handler;
|
|
138
|
-
});
|
|
139
|
-
options = { allowedAgentTypes: [AgentType.PRIVATE, AgentType.VASP] };
|
|
140
|
-
component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
141
|
-
url,
|
|
142
|
-
value,
|
|
143
|
-
options,
|
|
144
|
-
);
|
|
145
|
-
component.mount(parentId);
|
|
146
|
-
|
|
147
|
-
expect(messageHandler).toBeDefined();
|
|
148
|
-
messageHandler(handshake);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test('send', () => {
|
|
152
|
-
const message: HostMessage<Withdrawal, TransactionOptions> = {
|
|
153
|
-
type: HMType.UPDATE,
|
|
154
|
-
value: {
|
|
155
|
-
requestId: 'id',
|
|
156
|
-
},
|
|
157
|
-
options: { allowedAgentTypes: [AgentType.PRIVATE] },
|
|
158
|
-
};
|
|
159
|
-
component.send(message);
|
|
160
|
-
expect(port.postMessage).toHaveBeenCalledWith(message);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe('update', () => {
|
|
164
|
-
test('with out options', () => {
|
|
165
|
-
const newValue: Partial<Transaction> = { amountDecimal: 200 };
|
|
166
|
-
|
|
167
|
-
const message: HostMessage<Withdrawal, TransactionOptions> = {
|
|
168
|
-
type: HMType.UPDATE,
|
|
169
|
-
value: newValue,
|
|
170
|
-
options,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
component.update(newValue);
|
|
174
|
-
|
|
175
|
-
expect(component.value).toBe(newValue);
|
|
176
|
-
expect(component.options).toBe(options);
|
|
177
|
-
expect(port.postMessage).toHaveBeenCalledWith(message);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test('with options', () => {
|
|
181
|
-
const newValue: Partial<Transaction> = { amountDecimal: 200 };
|
|
182
|
-
const newOptions = { allowedAgentTypes: [AgentType.PRIVATE] };
|
|
183
|
-
|
|
184
|
-
const message: HostMessage<Withdrawal, TransactionOptions> = {
|
|
185
|
-
type: HMType.UPDATE,
|
|
186
|
-
value: newValue,
|
|
187
|
-
options: newOptions,
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
component.update(newValue, newOptions);
|
|
191
|
-
|
|
192
|
-
expect(component.value).toBe(newValue);
|
|
193
|
-
expect(component.options).toBe(newOptions);
|
|
194
|
-
expect(port.postMessage).toHaveBeenCalledWith(message);
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
// TODO not sure this actually does what I want it to do
|
|
198
|
-
describe('completion', () => {
|
|
199
|
-
test('resolves with response and cleans up listeners', async () => {
|
|
200
|
-
const response = { valid: true, value: 'completed' };
|
|
201
|
-
const completionPromise = component.completion();
|
|
202
|
-
|
|
203
|
-
port.onmessage!({
|
|
204
|
-
data: { type: CMType.COMPLETE, response },
|
|
205
|
-
} as unknown as MessageEvent);
|
|
206
|
-
|
|
207
|
-
const result = await completionPromise;
|
|
208
|
-
expect(result).toBe(response);
|
|
209
|
-
|
|
210
|
-
// Verify cleanup by sending another complete message - should not trigger anything
|
|
211
|
-
port.onmessage!({
|
|
212
|
-
data: { type: CMType.COMPLETE, response: { valid: false } },
|
|
213
|
-
} as unknown as MessageEvent);
|
|
214
|
-
|
|
215
|
-
// Original result should remain unchanged
|
|
216
|
-
expect(result).toBe(response);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
test('rejects with error and cleans up listeners', async () => {
|
|
220
|
-
const errorMessage = 'Test error';
|
|
221
|
-
const completionPromise = component.completion();
|
|
222
|
-
|
|
223
|
-
port.onmessage!({
|
|
224
|
-
data: { type: 'error', message: errorMessage },
|
|
225
|
-
} as unknown as MessageEvent);
|
|
226
|
-
|
|
227
|
-
await expect(completionPromise).rejects.toThrow(errorMessage);
|
|
228
|
-
|
|
229
|
-
// Verify cleanup by sending another error - should not trigger anything
|
|
230
|
-
port.onmessage!({
|
|
231
|
-
data: { type: 'error', message: 'Different error' },
|
|
232
|
-
} as unknown as MessageEvent);
|
|
233
|
-
|
|
234
|
-
// Original rejection should remain
|
|
235
|
-
await expect(completionPromise).rejects.toThrow(errorMessage);
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
describe('modal', () => {
|
|
242
|
-
let document: Document;
|
|
243
|
-
let dialog: HTMLDialogElement;
|
|
244
|
-
let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
|
|
245
|
-
|
|
246
|
-
beforeEach(() => {
|
|
247
|
-
dialog = {
|
|
248
|
-
style: {},
|
|
249
|
-
showModal: vi.fn(),
|
|
250
|
-
close: vi.fn(),
|
|
251
|
-
remove: vi.fn(),
|
|
252
|
-
addEventListener: vi.fn(),
|
|
253
|
-
appendChild: vi.fn(), // Add this
|
|
254
|
-
} as unknown as HTMLDialogElement;
|
|
255
|
-
|
|
256
|
-
document = {
|
|
257
|
-
createElement: vi.fn().mockImplementation((tag) => {
|
|
258
|
-
if (tag === 'dialog') return dialog;
|
|
259
|
-
if (tag === 'iframe')
|
|
260
|
-
return {
|
|
261
|
-
style: {},
|
|
262
|
-
contentWindow: { focus: vi.fn() },
|
|
263
|
-
addEventListener: vi.fn(),
|
|
264
|
-
} as unknown as HTMLIFrameElement;
|
|
265
|
-
}),
|
|
266
|
-
body: {
|
|
267
|
-
appendChild: vi.fn(),
|
|
268
|
-
},
|
|
269
|
-
} as unknown as Document;
|
|
270
|
-
|
|
271
|
-
const mockDoc = document;
|
|
272
|
-
vi.stubGlobal('document', mockDoc); // Use intermediate variable
|
|
273
|
-
|
|
274
|
-
component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
275
|
-
url,
|
|
276
|
-
value,
|
|
277
|
-
);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
afterEach(() => {
|
|
281
|
-
vi.unstubAllGlobals();
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
test('modal closes on cancel message', () => {
|
|
285
|
-
component.openModal();
|
|
286
|
-
|
|
287
|
-
// Trigger cancel message through event manager
|
|
288
|
-
component['eventManager']['handleMessage']({
|
|
289
|
-
data: { type: CMType.CANCEL },
|
|
290
|
-
} as MessageEvent);
|
|
291
|
-
|
|
292
|
-
expect(dialog.close).toHaveBeenCalled();
|
|
293
|
-
expect(dialog.remove).toHaveBeenCalled();
|
|
294
|
-
// await expect(completionPromise).rejects.toThrow();
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
test('modal closes on completion', async () => {
|
|
298
|
-
const completionPromise = component.openModal();
|
|
299
|
-
const response = { valid: true, value: 'completed' };
|
|
300
|
-
|
|
301
|
-
// Trigger complete message through event manager
|
|
302
|
-
component['eventManager']['handleMessage']({
|
|
303
|
-
data: { type: CMType.COMPLETE, response },
|
|
304
|
-
} as MessageEvent);
|
|
305
|
-
|
|
306
|
-
expect(dialog.close).toHaveBeenCalled();
|
|
307
|
-
expect(dialog.remove).toHaveBeenCalled();
|
|
308
|
-
await expect(completionPromise).resolves.toBe(response);
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
describe('error handling', () => {
|
|
313
|
-
let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
|
|
314
|
-
let mockMessageManager: (typeof component)['eventManager'];
|
|
315
|
-
let document: Document;
|
|
316
|
-
let parentElement: HTMLElement;
|
|
317
|
-
|
|
318
|
-
beforeEach(() => {
|
|
319
|
-
parentElement = {
|
|
320
|
-
appendChild: vi.fn(),
|
|
321
|
-
} as unknown as HTMLElement;
|
|
322
|
-
|
|
323
|
-
document = {
|
|
324
|
-
createElement: vi.fn().mockReturnValue({
|
|
325
|
-
style: {},
|
|
326
|
-
contentWindow: { focus: vi.fn() },
|
|
327
|
-
} as unknown as HTMLIFrameElement),
|
|
328
|
-
querySelector: vi.fn().mockReturnValue(parentElement),
|
|
329
|
-
} as unknown as Document;
|
|
330
|
-
|
|
331
|
-
const mockDoc = document;
|
|
332
|
-
vi.stubGlobal('document', mockDoc);
|
|
333
|
-
|
|
334
|
-
component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
335
|
-
url,
|
|
336
|
-
value,
|
|
337
|
-
);
|
|
338
|
-
mockMessageManager = component['eventManager'];
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
test('handles invalid messages', () => {
|
|
342
|
-
const errors = [{ attribute: 'test', message: 'error' }];
|
|
343
|
-
const newValue = { ...value, extra: 'data' };
|
|
344
|
-
|
|
345
|
-
mockMessageManager['handleMessage']({
|
|
346
|
-
data: {
|
|
347
|
-
type: CMType.INVALID,
|
|
348
|
-
errors,
|
|
349
|
-
value: newValue,
|
|
350
|
-
},
|
|
351
|
-
} as MessageEvent);
|
|
352
|
-
|
|
353
|
-
expect(component.errors).toEqual(errors);
|
|
354
|
-
expect(component.value).toEqual(newValue);
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
test('handles resize messages', () => {
|
|
358
|
-
const mockIframe = {
|
|
359
|
-
style: {},
|
|
360
|
-
contentWindow: { focus: vi.fn() },
|
|
361
|
-
} as unknown as HTMLIFrameElement;
|
|
362
|
-
|
|
363
|
-
document.createElement = vi.fn().mockReturnValue(mockIframe);
|
|
364
|
-
document.querySelector = vi.fn().mockReturnValue(parentElement);
|
|
365
|
-
|
|
366
|
-
component.mount(parentId);
|
|
367
|
-
|
|
368
|
-
mockMessageManager['handleMessage']({
|
|
369
|
-
data: {
|
|
370
|
-
type: CMType.RESIZE,
|
|
371
|
-
height: 500,
|
|
372
|
-
},
|
|
373
|
-
} as MessageEvent);
|
|
374
|
-
|
|
375
|
-
expect(mockIframe.style.height).toBe('500px');
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
describe('event management', () => {
|
|
380
|
-
let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
|
|
381
|
-
let mockWindow: Window;
|
|
382
|
-
beforeEach(() => {
|
|
383
|
-
// Create a mock window without modifying global
|
|
384
|
-
mockWindow = {
|
|
385
|
-
addEventListener: vi.fn(),
|
|
386
|
-
dispatchEvent: vi.fn(),
|
|
387
|
-
} as unknown as Window;
|
|
388
|
-
|
|
389
|
-
vi.stubGlobal('window', mockWindow);
|
|
390
|
-
|
|
391
|
-
component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
392
|
-
url,
|
|
393
|
-
value,
|
|
394
|
-
);
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
afterEach(() => {
|
|
398
|
-
vi.unstubAllGlobals();
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
test('multiple listeners for same event type', () => {
|
|
402
|
-
const callback1 = vi.fn();
|
|
403
|
-
const callback2 = vi.fn();
|
|
404
|
-
|
|
405
|
-
component.on('test', callback1);
|
|
406
|
-
component.on('test', callback2);
|
|
407
|
-
|
|
408
|
-
// Trigger message via component's event manager
|
|
409
|
-
component['eventManager']['handleMessage']({
|
|
410
|
-
data: { type: 'test', payload: 'data' },
|
|
411
|
-
} as MessageEvent);
|
|
412
|
-
|
|
413
|
-
expect(callback1).toHaveBeenCalled();
|
|
414
|
-
expect(callback2).toHaveBeenCalled();
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
test('removal of specific listener', () => {
|
|
418
|
-
const callback1 = vi.fn();
|
|
419
|
-
const callback2 = vi.fn();
|
|
420
|
-
|
|
421
|
-
component.on('test', callback1);
|
|
422
|
-
component.on('test', callback2);
|
|
423
|
-
component.off('test', callback1);
|
|
424
|
-
|
|
425
|
-
component['eventManager']['handleMessage']({
|
|
426
|
-
data: { type: 'test', payload: 'data' },
|
|
427
|
-
} as MessageEvent);
|
|
428
|
-
|
|
429
|
-
expect(callback1).not.toHaveBeenCalled();
|
|
430
|
-
expect(callback2).toHaveBeenCalled();
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
describe('cleanup', () => {
|
|
435
|
-
let mockIframe: HTMLIFrameElement;
|
|
436
|
-
let parentElement: HTMLElement;
|
|
437
|
-
let document: Document;
|
|
438
|
-
|
|
439
|
-
beforeEach(() => {
|
|
440
|
-
mockIframe = {
|
|
441
|
-
style: {},
|
|
442
|
-
src: '',
|
|
443
|
-
contentWindow: {
|
|
444
|
-
focus: vi.fn(),
|
|
445
|
-
} as unknown as Window,
|
|
446
|
-
remove: vi.fn(),
|
|
447
|
-
} as unknown as HTMLIFrameElement;
|
|
448
|
-
|
|
449
|
-
parentElement = {
|
|
450
|
-
appendChild: vi.fn(),
|
|
451
|
-
} as unknown as HTMLElement;
|
|
452
|
-
|
|
453
|
-
document = {
|
|
454
|
-
createElement: vi.fn().mockReturnValue(mockIframe),
|
|
455
|
-
querySelector: vi.fn().mockReturnValue(parentElement),
|
|
456
|
-
} as unknown as Document;
|
|
457
|
-
|
|
458
|
-
const mockDoc = document;
|
|
459
|
-
vi.stubGlobal('document', mockDoc);
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
afterEach(() => {
|
|
463
|
-
vi.unstubAllGlobals();
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
test('removeEmbed cleans up iframe', () => {
|
|
467
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
468
|
-
url,
|
|
469
|
-
value,
|
|
470
|
-
);
|
|
471
|
-
component.mount(parentId);
|
|
472
|
-
|
|
473
|
-
component.removeEmbed();
|
|
474
|
-
expect(mockIframe.remove).toHaveBeenCalled();
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
test('cleanup on unmount', () => {
|
|
478
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
479
|
-
url,
|
|
480
|
-
value,
|
|
481
|
-
);
|
|
482
|
-
const callback = vi.fn();
|
|
483
|
-
component.on('test', callback);
|
|
484
|
-
|
|
485
|
-
component.mount(parentId);
|
|
486
|
-
|
|
487
|
-
component.removeEmbed();
|
|
488
|
-
|
|
489
|
-
// Create a new event manager to simulate cleanup
|
|
490
|
-
component['eventManager'] = new MessageEventManager();
|
|
491
|
-
|
|
492
|
-
// Try to trigger message after cleanup
|
|
493
|
-
component['eventManager']['handleMessage']({
|
|
494
|
-
data: { type: 'test', payload: 'data' },
|
|
495
|
-
} as MessageEvent);
|
|
496
|
-
|
|
497
|
-
expect(callback).not.toHaveBeenCalled();
|
|
498
|
-
});
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
describe('state management', () => {
|
|
502
|
-
test('maintains value and options state', () => {
|
|
503
|
-
const initialValue = { amountDecimal: 100 };
|
|
504
|
-
const initialOptions = { allowedAgentTypes: [AgentType.PRIVATE] };
|
|
505
|
-
|
|
506
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
507
|
-
url,
|
|
508
|
-
initialValue,
|
|
509
|
-
initialOptions,
|
|
510
|
-
);
|
|
511
|
-
|
|
512
|
-
expect(component.value).toEqual(initialValue);
|
|
513
|
-
expect(component.options).toEqual(initialOptions);
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
test('updates maintain state consistency', () => {
|
|
517
|
-
const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
|
|
518
|
-
url,
|
|
519
|
-
value,
|
|
520
|
-
);
|
|
521
|
-
const newValue = { amountDecimal: 200 };
|
|
522
|
-
const newOptions = { allowedAgentTypes: [AgentType.VASP] };
|
|
523
|
-
|
|
524
|
-
component.update(newValue, newOptions);
|
|
525
|
-
|
|
526
|
-
expect(component.value).toEqual(newValue);
|
|
527
|
-
expect(component.options).toEqual(newOptions);
|
|
528
|
-
});
|
|
529
|
-
});
|
|
530
|
-
});
|