@notabene/javascript-sdk 2.7.0 → 2.7.1-next.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/dist/notabene.d.ts +11 -2
- package/package.json +1 -1
- package/src/__tests__/EmbeddedComponent.test.ts +222 -0
- package/src/types.ts +17 -2
package/dist/notabene.d.ts
CHANGED
|
@@ -383,7 +383,7 @@ export declare function decodeFragmentToObject(fragment: string): Record<string,
|
|
|
383
383
|
* An object representing a deposit transaction
|
|
384
384
|
* @public
|
|
385
385
|
*/
|
|
386
|
-
export declare interface Deposit extends OriginatorFields, DepositTransaction {
|
|
386
|
+
export declare interface Deposit extends OriginatorFields, DepositTransaction, Refreshable {
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
/**
|
|
@@ -1262,6 +1262,15 @@ export declare type Ready = {
|
|
|
1262
1262
|
type: CMType.READY;
|
|
1263
1263
|
};
|
|
1264
1264
|
|
|
1265
|
+
declare interface Refreshable {
|
|
1266
|
+
refreshSource?: RefreshSource;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
declare interface RefreshSource {
|
|
1270
|
+
url: URI;
|
|
1271
|
+
key: string;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1265
1274
|
declare type RequestID = UUID;
|
|
1266
1275
|
|
|
1267
1276
|
/**
|
|
@@ -1628,7 +1637,7 @@ export declare interface Wallet extends Agent {
|
|
|
1628
1637
|
* An object representing a withdrawal transaction
|
|
1629
1638
|
* @public
|
|
1630
1639
|
*/
|
|
1631
|
-
export declare interface Withdrawal extends BeneficiaryFields, Transaction {
|
|
1640
|
+
export declare interface Withdrawal extends BeneficiaryFields, Transaction, Refreshable {
|
|
1632
1641
|
}
|
|
1633
1642
|
|
|
1634
1643
|
export { }
|
package/package.json
CHANGED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import EmbeddedComponent from '../components/EmbeddedComponent';
|
|
3
|
+
import { CMType, HMType } from '../types';
|
|
4
|
+
|
|
5
|
+
// Simple test interfaces
|
|
6
|
+
interface TestValue {
|
|
7
|
+
name?: string;
|
|
8
|
+
amount?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface TestOptions {
|
|
12
|
+
currency?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Mock MessageEventManager
|
|
16
|
+
vi.mock('../utils/MessageEventManager', () => {
|
|
17
|
+
return {
|
|
18
|
+
MessageEventManager: vi.fn().mockImplementation(() => ({
|
|
19
|
+
on: vi.fn((type, callback) => {
|
|
20
|
+
callbacks.set(type, callback);
|
|
21
|
+
return () => callbacks.delete(type);
|
|
22
|
+
}),
|
|
23
|
+
send: vi.fn((message) => {
|
|
24
|
+
const callback = callbacks.get(message.type);
|
|
25
|
+
if (callback) callback(message);
|
|
26
|
+
}),
|
|
27
|
+
off: vi.fn(),
|
|
28
|
+
setPort: vi.fn(),
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Store callbacks for testing
|
|
34
|
+
const callbacks = new Map();
|
|
35
|
+
|
|
36
|
+
describe('EmbeddedComponent', () => {
|
|
37
|
+
let mockParent: HTMLElement;
|
|
38
|
+
let mockAppendChild: ReturnType<typeof vi.fn>;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
// Clear callbacks before each test
|
|
42
|
+
callbacks.clear();
|
|
43
|
+
|
|
44
|
+
mockParent = document.createElement('div');
|
|
45
|
+
vi.spyOn(document, 'querySelector').mockReturnValue(mockParent);
|
|
46
|
+
mockAppendChild = vi.fn().mockImplementation((node: Node) => node);
|
|
47
|
+
vi.spyOn(mockParent, 'appendChild').mockImplementation(mockAppendChild);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('initialization', () => {
|
|
51
|
+
test('should initialize with basic values', () => {
|
|
52
|
+
const url = 'https://example.com';
|
|
53
|
+
const value = { name: 'Test' };
|
|
54
|
+
const options = { currency: 'USD' };
|
|
55
|
+
|
|
56
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
57
|
+
url,
|
|
58
|
+
value,
|
|
59
|
+
options,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
expect(component.url).toBe(url);
|
|
63
|
+
expect(component.value).toEqual(value);
|
|
64
|
+
expect(component.options).toEqual(options);
|
|
65
|
+
expect(component.errors).toEqual([]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should initialize without options', () => {
|
|
69
|
+
const url = 'https://example.com';
|
|
70
|
+
const value = { name: 'Test' };
|
|
71
|
+
|
|
72
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
73
|
+
url,
|
|
74
|
+
value,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(component.url).toBe(url);
|
|
78
|
+
expect(component.value).toEqual(value);
|
|
79
|
+
expect(component.options).toBeUndefined();
|
|
80
|
+
expect(component.errors).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('value updates', () => {
|
|
85
|
+
test('should update value', () => {
|
|
86
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
87
|
+
'https://example.com',
|
|
88
|
+
{},
|
|
89
|
+
);
|
|
90
|
+
const newValue = { name: 'Updated', amount: 100 };
|
|
91
|
+
|
|
92
|
+
component.update(newValue);
|
|
93
|
+
|
|
94
|
+
expect(component.value).toEqual(newValue);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should update value and options', () => {
|
|
98
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
99
|
+
'https://example.com',
|
|
100
|
+
{},
|
|
101
|
+
);
|
|
102
|
+
const newValue = { name: 'Updated', amount: 100 };
|
|
103
|
+
const newOptions = { currency: 'EUR' };
|
|
104
|
+
|
|
105
|
+
component.update(newValue, newOptions);
|
|
106
|
+
|
|
107
|
+
expect(component.value).toEqual(newValue);
|
|
108
|
+
expect(component.options).toEqual(newOptions);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('mounting', () => {
|
|
113
|
+
test('should mount component to parent element', () => {
|
|
114
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
115
|
+
'https://example.com',
|
|
116
|
+
{},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
component.mount('#parent');
|
|
120
|
+
|
|
121
|
+
expect(document.querySelector).toHaveBeenCalledWith('#parent');
|
|
122
|
+
const iframe = mockAppendChild.mock.calls[0][0] as HTMLIFrameElement;
|
|
123
|
+
expect(iframe).toBeTruthy();
|
|
124
|
+
expect(iframe.src).toBe('https://example.com&embedded=true/');
|
|
125
|
+
expect(iframe.style.width).toBe('100%');
|
|
126
|
+
expect(iframe.style.height).toBe('0px');
|
|
127
|
+
expect(iframe.style.border).toBe('');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('should throw error if parent element not found', () => {
|
|
131
|
+
vi.spyOn(document, 'querySelector').mockReturnValue(null);
|
|
132
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
133
|
+
'https://example.com',
|
|
134
|
+
{},
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
expect(() => component.mount('#nonexistent')).toThrow(
|
|
138
|
+
'parentID #nonexistent not found',
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('should remove existing iframe when mounting again', () => {
|
|
143
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
144
|
+
'https://example.com',
|
|
145
|
+
{},
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// First mount
|
|
149
|
+
component.mount('#parent');
|
|
150
|
+
const firstIframe = mockAppendChild.mock.calls[0][0] as HTMLIFrameElement;
|
|
151
|
+
const removeSpy = vi.spyOn(firstIframe, 'remove');
|
|
152
|
+
|
|
153
|
+
// Second mount
|
|
154
|
+
component.mount('#parent');
|
|
155
|
+
|
|
156
|
+
expect(removeSpy).toHaveBeenCalled();
|
|
157
|
+
expect(mockAppendChild).toHaveBeenCalledTimes(2);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('event handling', () => {
|
|
162
|
+
test('should register and unregister event listeners', () => {
|
|
163
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
164
|
+
'https://example.com',
|
|
165
|
+
{},
|
|
166
|
+
);
|
|
167
|
+
const mockCallback = vi.fn();
|
|
168
|
+
|
|
169
|
+
// Register event listener
|
|
170
|
+
const unsubscribe = component.on(HMType.UPDATE, mockCallback);
|
|
171
|
+
|
|
172
|
+
// Send a message
|
|
173
|
+
component.send({ type: HMType.UPDATE, value: { name: 'test' } });
|
|
174
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
175
|
+
expect(mockCallback).toHaveBeenCalledWith({
|
|
176
|
+
type: HMType.UPDATE,
|
|
177
|
+
value: { name: 'test' },
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Unsubscribe and send again
|
|
181
|
+
unsubscribe();
|
|
182
|
+
component.send({ type: HMType.UPDATE, value: { name: 'test2' } });
|
|
183
|
+
expect(mockCallback).toHaveBeenCalledTimes(1); // Still 1, not called again
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test('should handle resize events', () => {
|
|
187
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
188
|
+
'https://example.com',
|
|
189
|
+
{},
|
|
190
|
+
);
|
|
191
|
+
component.mount('#parent');
|
|
192
|
+
|
|
193
|
+
const iframe = mockAppendChild.mock.calls[0][0] as HTMLIFrameElement;
|
|
194
|
+
|
|
195
|
+
// Get the resize callback and trigger it directly
|
|
196
|
+
const resizeCallback = callbacks.get(CMType.RESIZE);
|
|
197
|
+
resizeCallback({ type: CMType.RESIZE, height: 500 });
|
|
198
|
+
|
|
199
|
+
expect(iframe.style.height).toBe('500px');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('should handle validation errors', () => {
|
|
203
|
+
const component = new EmbeddedComponent<TestValue, TestOptions>(
|
|
204
|
+
'https://example.com',
|
|
205
|
+
{},
|
|
206
|
+
);
|
|
207
|
+
const mockErrors = [{ field: 'name', message: 'Required' }];
|
|
208
|
+
const mockValue = { name: '' };
|
|
209
|
+
|
|
210
|
+
// Get the validation callback and trigger it directly
|
|
211
|
+
const validationCallback = callbacks.get(CMType.INVALID);
|
|
212
|
+
validationCallback({
|
|
213
|
+
type: CMType.INVALID,
|
|
214
|
+
errors: mockErrors,
|
|
215
|
+
value: mockValue,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
expect(component.errors).toEqual(mockErrors);
|
|
219
|
+
expect(component.value).toEqual(mockValue);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
package/src/types.ts
CHANGED
|
@@ -531,6 +531,15 @@ export interface Transaction extends ComponentRequest {
|
|
|
531
531
|
};
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
export interface RefreshSource {
|
|
535
|
+
url: URI;
|
|
536
|
+
key: string;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export interface Refreshable {
|
|
540
|
+
refreshSource?: RefreshSource;
|
|
541
|
+
}
|
|
542
|
+
|
|
534
543
|
/**
|
|
535
544
|
* Extended transaction interface for deposits
|
|
536
545
|
* @public
|
|
@@ -543,13 +552,19 @@ export interface DepositTransaction extends Transaction {
|
|
|
543
552
|
* An object representing a withdrawal transaction
|
|
544
553
|
* @public
|
|
545
554
|
*/
|
|
546
|
-
export interface Withdrawal
|
|
555
|
+
export interface Withdrawal
|
|
556
|
+
extends BeneficiaryFields,
|
|
557
|
+
Transaction,
|
|
558
|
+
Refreshable {}
|
|
547
559
|
|
|
548
560
|
/**
|
|
549
561
|
* An object representing a deposit transaction
|
|
550
562
|
* @public
|
|
551
563
|
*/
|
|
552
|
-
export interface Deposit
|
|
564
|
+
export interface Deposit
|
|
565
|
+
extends OriginatorFields,
|
|
566
|
+
DepositTransaction,
|
|
567
|
+
Refreshable {}
|
|
553
568
|
|
|
554
569
|
/**
|
|
555
570
|
* An object representing a request for a deposit
|