@osimatic/helpers-js 1.4.24 → 1.4.26
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/.claude/settings.local.json +2 -1
- package/chartjs.js +1 -1
- package/date_time.js +25 -16
- package/draw.js +3 -2
- package/duration.js +176 -130
- package/event_bus.js +2 -2
- package/file.js +20 -5
- package/form_helper.js +1 -1
- package/google_charts.js +2 -1
- package/http_client.js +2 -0
- package/jwt.js +18 -6
- package/location.js +5 -1
- package/media.js +7 -7
- package/multi_files_input.js +3 -1
- package/number.js +2 -3
- package/package.json +4 -2
- package/paging.js +2 -2
- package/social_network.js +5 -0
- package/string.js +11 -2
- package/tests/__mocks__/socket.io-client.js +13 -0
- package/tests/chartjs.test.js +273 -0
- package/tests/count_down.test.js +580 -0
- package/tests/date_time/DatePeriod.test.js +179 -0
- package/tests/date_time/DateTime.test.js +492 -0
- package/tests/date_time/SqlDate.test.js +205 -0
- package/tests/date_time/SqlDateTime.test.js +326 -0
- package/tests/date_time/SqlTime.test.js +162 -0
- package/tests/date_time/TimestampUnix.test.js +262 -0
- package/tests/details_sub_array.test.js +367 -0
- package/tests/draw.test.js +271 -0
- package/tests/duration.test.js +365 -0
- package/tests/event_bus.test.js +268 -0
- package/tests/file.test.js +568 -0
- package/tests/flash_message.test.js +297 -0
- package/tests/form_date.test.js +1559 -0
- package/tests/form_helper.test.js +1065 -0
- package/tests/google_charts.test.js +768 -0
- package/tests/google_maps.test.js +655 -0
- package/tests/google_recaptcha.test.js +441 -0
- package/tests/http_client.test.js +570 -0
- package/tests/import_from_csv.test.js +797 -0
- package/tests/jwt.test.js +804 -0
- package/tests/list_box.test.js +255 -0
- package/tests/location.test.js +86 -0
- package/tests/media.test.js +473 -0
- package/tests/multi_files_input.test.js +1015 -0
- package/tests/multiple_action_in_table.test.js +477 -0
- package/tests/network.test.js +489 -0
- package/tests/number.test.js +448 -0
- package/tests/open_street_map.test.js +388 -0
- package/tests/paging.test.js +646 -0
- package/tests/select_all.test.js +360 -0
- package/tests/shopping_cart.test.js +355 -0
- package/tests/social_network.test.js +333 -0
- package/tests/sortable_list.test.js +602 -0
- package/tests/string.test.js +489 -0
- package/tests/user.test.js +204 -0
- package/tests/util.test.js +99 -0
- package/tests/visitor.test.js +508 -0
- package/tests/web_rtc.test.js +458 -0
- package/tests/web_socket.test.js +538 -0
- package/visitor.js +2 -2
- package/tmpclaude-0fa4-cwd +0 -1
- package/tmpclaude-104f-cwd +0 -1
- package/tmpclaude-1468-cwd +0 -1
- package/tmpclaude-324b-cwd +0 -1
- package/tmpclaude-35d3-cwd +0 -1
- package/tmpclaude-4aa8-cwd +0 -1
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
const { File, CSV, Img } = require('../file');
|
|
2
|
+
|
|
3
|
+
describe('File', () => {
|
|
4
|
+
describe('formatFileSize', () => {
|
|
5
|
+
test('should format zero bytes', () => {
|
|
6
|
+
const result = File.formatFileSize(0);
|
|
7
|
+
expect(result).toBe('0 kB');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('should format bytes to kB', () => {
|
|
11
|
+
const result = File.formatFileSize(1024);
|
|
12
|
+
expect(result).toContain('1');
|
|
13
|
+
expect(result).toContain('kB');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should format bytes to MB', () => {
|
|
17
|
+
const result = File.formatFileSize(1024 * 1024);
|
|
18
|
+
expect(result).toContain('1');
|
|
19
|
+
expect(result).toContain('MB');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('should format bytes to GB', () => {
|
|
23
|
+
const result = File.formatFileSize(1024 * 1024 * 1024);
|
|
24
|
+
expect(result).toContain('1');
|
|
25
|
+
expect(result).toContain('GB');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should format bytes to TB', () => {
|
|
29
|
+
const result = File.formatFileSize(1024 * 1024 * 1024 * 1024);
|
|
30
|
+
expect(result).toContain('1');
|
|
31
|
+
expect(result).toContain('TB');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should format with custom fraction digits', () => {
|
|
35
|
+
const result = File.formatFileSize(1536, 0); // 1.5 kB
|
|
36
|
+
expect(result).toContain('kB');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should format with default 2 fraction digits', () => {
|
|
40
|
+
const result = File.formatFileSize(1536); // 1.5 kB
|
|
41
|
+
expect(result).toContain('1,5');
|
|
42
|
+
expect(result).toContain('kB');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should handle small values (min 0.1)', () => {
|
|
46
|
+
const result = File.formatFileSize(50);
|
|
47
|
+
expect(result).toContain('0,1');
|
|
48
|
+
expect(result).toContain('kB');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('should format with en-US locale', () => {
|
|
52
|
+
const result = File.formatFileSize(1536, 2, 'en-US');
|
|
53
|
+
expect(result).toContain('1.5');
|
|
54
|
+
expect(result).toContain('kB');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('should handle very large files', () => {
|
|
58
|
+
const result = File.formatFileSize(1024 * 1024 * 1024 * 1024 * 1024); // 1 PB
|
|
59
|
+
expect(result).toContain('PB');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should format complex size', () => {
|
|
63
|
+
const result = File.formatFileSize(5242880); // 5 MB
|
|
64
|
+
expect(result).toContain('5');
|
|
65
|
+
expect(result).toContain('MB');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should format with 3 fraction digits', () => {
|
|
69
|
+
const result = File.formatFileSize(1536, 3);
|
|
70
|
+
expect(result).toContain('1,5');
|
|
71
|
+
expect(result).toContain('kB');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('blobToBase64', () => {
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
// Mock FileReader
|
|
78
|
+
global.FileReader = jest.fn(function() {
|
|
79
|
+
this.readAsDataURL = jest.fn(function(blob) {
|
|
80
|
+
// Simulate async read
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
this.result = 'data:text/plain;base64,SGVsbG8=';
|
|
83
|
+
if (this.onload) {
|
|
84
|
+
this.onload();
|
|
85
|
+
}
|
|
86
|
+
}, 0);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('should convert blob to base64', (done) => {
|
|
92
|
+
const mockBlob = new Blob(['Hello'], { type: 'text/plain' });
|
|
93
|
+
|
|
94
|
+
File.blobToBase64(mockBlob, (result) => {
|
|
95
|
+
expect(result).toBe('data:text/plain;base64,SGVsbG8=');
|
|
96
|
+
done();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should call callback with result', (done) => {
|
|
101
|
+
const mockBlob = new Blob(['Test'], { type: 'text/plain' });
|
|
102
|
+
const callback = jest.fn((result) => {
|
|
103
|
+
expect(callback).toHaveBeenCalledWith('data:text/plain;base64,SGVsbG8=');
|
|
104
|
+
done();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
File.blobToBase64(mockBlob, callback);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('download', () => {
|
|
112
|
+
let mockBlob, mockURL, mockA;
|
|
113
|
+
|
|
114
|
+
beforeEach(() => {
|
|
115
|
+
// Mock Blob
|
|
116
|
+
global.Blob = jest.fn((content, options) => ({
|
|
117
|
+
content,
|
|
118
|
+
type: options.type
|
|
119
|
+
}));
|
|
120
|
+
|
|
121
|
+
// Mock URL.createObjectURL and revokeObjectURL
|
|
122
|
+
mockURL = {
|
|
123
|
+
createObjectURL: jest.fn(() => 'blob:mock-url'),
|
|
124
|
+
revokeObjectURL: jest.fn()
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Mock document.createElement
|
|
128
|
+
mockA = {
|
|
129
|
+
href: '',
|
|
130
|
+
download: '',
|
|
131
|
+
click: jest.fn(),
|
|
132
|
+
setAttribute: jest.fn()
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
global.document = {
|
|
136
|
+
createElement: jest.fn(() => mockA),
|
|
137
|
+
body: {
|
|
138
|
+
appendChild: jest.fn()
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
global.window = {
|
|
143
|
+
URL: mockURL,
|
|
144
|
+
navigator: {
|
|
145
|
+
msSaveBlob: undefined
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
jest.useFakeTimers();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
afterEach(() => {
|
|
153
|
+
jest.useRealTimers();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('should create blob with correct content type', () => {
|
|
157
|
+
File.download('test data', 'text/plain', 'attachment; filename="test.txt"');
|
|
158
|
+
|
|
159
|
+
expect(global.Blob).toHaveBeenCalledWith(['test data'], { type: 'text/plain' });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('should extract filename from content disposition', () => {
|
|
163
|
+
File.download('data', 'text/plain', 'attachment; filename="document.pdf"');
|
|
164
|
+
|
|
165
|
+
expect(mockA.download).toBe('document.pdf');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('should handle inline disposition', () => {
|
|
169
|
+
File.download('data', 'text/plain', 'inline; filename="image.png"');
|
|
170
|
+
|
|
171
|
+
expect(mockA.download).toBe('image.png');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('should use default filename when none provided', () => {
|
|
175
|
+
File.download('data', 'application/pdf', '');
|
|
176
|
+
|
|
177
|
+
expect(mockA.download).toBe('file.pdf');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('should create download link and trigger click', () => {
|
|
181
|
+
File.download('data', 'text/plain', 'attachment; filename="test.txt"');
|
|
182
|
+
|
|
183
|
+
expect(mockURL.createObjectURL).toHaveBeenCalled();
|
|
184
|
+
expect(mockA.href).toBe('blob:mock-url');
|
|
185
|
+
expect(document.body.appendChild).toHaveBeenCalledWith(mockA);
|
|
186
|
+
expect(mockA.click).toHaveBeenCalled();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('should revoke object URL after timeout', () => {
|
|
190
|
+
File.download('data', 'text/plain', 'attachment; filename="test.txt"');
|
|
191
|
+
|
|
192
|
+
jest.advanceTimersByTime(100);
|
|
193
|
+
|
|
194
|
+
expect(mockURL.revokeObjectURL).toHaveBeenCalledWith('blob:mock-url');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('should handle filename with quotes', () => {
|
|
198
|
+
File.download('data', 'text/plain', 'attachment; filename="test\'s file.txt"');
|
|
199
|
+
|
|
200
|
+
expect(mockA.download).toBe("tests file.txt");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('should handle IE with msSaveBlob', () => {
|
|
204
|
+
window.navigator.msSaveBlob = jest.fn();
|
|
205
|
+
|
|
206
|
+
File.download('data', 'text/plain', 'attachment; filename="test.txt"');
|
|
207
|
+
|
|
208
|
+
expect(window.navigator.msSaveBlob).toHaveBeenCalled();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('CSV', () => {
|
|
214
|
+
describe('checkFile', () => {
|
|
215
|
+
test('should return true for valid CSV file with text/csv type', () => {
|
|
216
|
+
expect(CSV.checkFile('data.csv', 'text/csv')).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('should return true for valid CSV file with application/vnd.ms-excel type', () => {
|
|
220
|
+
expect(CSV.checkFile('report.csv', 'application/vnd.ms-excel')).toBe(true);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('should return false for CSV file with wrong mime type', () => {
|
|
224
|
+
expect(CSV.checkFile('data.csv', 'application/json')).toBe(false);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('should return false for non-CSV file with CSV mime type', () => {
|
|
228
|
+
expect(CSV.checkFile('data.txt', 'text/csv')).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('should return false for xlsx file', () => {
|
|
232
|
+
expect(CSV.checkFile('data.xlsx', 'application/vnd.ms-excel')).toBe(false);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('should handle uppercase extension', () => {
|
|
236
|
+
expect(CSV.checkFile('data.CSV', 'text/csv')).toBe(true);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test('should handle mixed case extension', () => {
|
|
240
|
+
expect(CSV.checkFile('data.CsV', 'text/csv')).toBe(true);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test('should handle filename with multiple dots', () => {
|
|
244
|
+
expect(CSV.checkFile('my.data.file.csv', 'text/csv')).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('should return true for application/octet-stream', () => {
|
|
248
|
+
expect(CSV.checkFile('data.csv', 'application/octet-stream')).toBe(true);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('should return true for text/plain', () => {
|
|
252
|
+
expect(CSV.checkFile('data.csv', 'text/plain')).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test('should return false for empty filename', () => {
|
|
256
|
+
expect(CSV.checkFile('', 'text/csv')).toBe(false);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('should return false for filename without extension', () => {
|
|
260
|
+
expect(CSV.checkFile('data', 'text/csv')).toBe(false);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe('Img', () => {
|
|
266
|
+
describe('compress', () => {
|
|
267
|
+
test('should compress data by extracting non-zero values', () => {
|
|
268
|
+
const data = new Uint8Array([65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0]);
|
|
269
|
+
const result = Img.compress(data);
|
|
270
|
+
expect(result).toBe('ABC');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test('should handle empty array', () => {
|
|
274
|
+
const data = new Uint8Array([]);
|
|
275
|
+
const result = Img.compress(data);
|
|
276
|
+
expect(result).toBe('');
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test('should handle all zero values', () => {
|
|
280
|
+
const data = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]);
|
|
281
|
+
const result = Img.compress(data);
|
|
282
|
+
expect(result).toBe('');
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test('should handle array with one non-zero value', () => {
|
|
286
|
+
const data = new Uint8Array([72, 0, 0, 0]);
|
|
287
|
+
const result = Img.compress(data);
|
|
288
|
+
expect(result).toBe('H');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test('should handle special characters', () => {
|
|
292
|
+
const data = new Uint8Array([33, 0, 0, 0, 64, 0, 0, 0, 35, 0, 0, 0]);
|
|
293
|
+
const result = Img.compress(data);
|
|
294
|
+
expect(result).toBe('!@#');
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('should only read every 4th byte', () => {
|
|
298
|
+
const data = new Uint8Array([65, 66, 67, 68, 69, 70, 71, 72]);
|
|
299
|
+
const result = Img.compress(data);
|
|
300
|
+
expect(result).toBe('AE');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test('should handle ASCII printable characters', () => {
|
|
304
|
+
const data = new Uint8Array([72, 0, 0, 0, 101, 0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0]);
|
|
305
|
+
const result = Img.compress(data);
|
|
306
|
+
expect(result).toBe('Hello');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test('should skip zero values in first position', () => {
|
|
310
|
+
const data = new Uint8Array([0, 0, 0, 0, 65, 0, 0, 0]);
|
|
311
|
+
const result = Img.compress(data);
|
|
312
|
+
expect(result).toBe('A');
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('setBlobToImg', () => {
|
|
317
|
+
let mockImg;
|
|
318
|
+
let mockURL;
|
|
319
|
+
let consoleErrorSpy;
|
|
320
|
+
let RealBlob;
|
|
321
|
+
let MockBlob;
|
|
322
|
+
|
|
323
|
+
beforeEach(() => {
|
|
324
|
+
// Save real Blob before any mocking
|
|
325
|
+
RealBlob = global.Blob;
|
|
326
|
+
|
|
327
|
+
// Create a MockBlob class that passes instanceof checks
|
|
328
|
+
MockBlob = class MockBlob {
|
|
329
|
+
constructor(content, options) {
|
|
330
|
+
this.content = content;
|
|
331
|
+
this.type = options?.type || '';
|
|
332
|
+
this.size = content && content.length ? content.reduce((sum, part) => sum + part.length, 0) : 0;
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// Set global.Blob to our MockBlob so instanceof checks pass
|
|
337
|
+
global.Blob = MockBlob;
|
|
338
|
+
|
|
339
|
+
// Mock jQuery image element with length property (essential for jQuery objects)
|
|
340
|
+
mockImg = {
|
|
341
|
+
attr: jest.fn().mockReturnThis(),
|
|
342
|
+
length: 1 // Valid jQuery object has length > 0
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// Mock URL.createObjectURL
|
|
346
|
+
mockURL = {
|
|
347
|
+
createObjectURL: jest.fn(() => 'blob:mock-url-12345')
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
global.window = {
|
|
351
|
+
URL: mockURL
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// Spy on console.error
|
|
355
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
afterEach(() => {
|
|
359
|
+
delete global.window;
|
|
360
|
+
consoleErrorSpy.mockRestore();
|
|
361
|
+
// Restore real Blob if it was changed
|
|
362
|
+
if (RealBlob) {
|
|
363
|
+
global.Blob = RealBlob;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('should create object URL from blob', () => {
|
|
368
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
369
|
+
|
|
370
|
+
Img.setBlobToImg(mockImg, mockBlob);
|
|
371
|
+
|
|
372
|
+
expect(mockURL.createObjectURL).toHaveBeenCalledWith(mockBlob);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
test('should set img src attribute with created URL', () => {
|
|
376
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
377
|
+
|
|
378
|
+
Img.setBlobToImg(mockImg, mockBlob);
|
|
379
|
+
|
|
380
|
+
expect(mockImg.attr).toHaveBeenCalledWith('src', 'blob:mock-url-12345');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test('should handle different blob types', () => {
|
|
384
|
+
const mockBlob = new Blob(['data'], { type: 'image/jpeg' });
|
|
385
|
+
|
|
386
|
+
Img.setBlobToImg(mockImg, mockBlob);
|
|
387
|
+
|
|
388
|
+
expect(mockURL.createObjectURL).toHaveBeenCalledWith(mockBlob);
|
|
389
|
+
expect(mockImg.attr).toHaveBeenCalledWith('src', 'blob:mock-url-12345');
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
test('should use webkitURL as fallback when URL is not available', () => {
|
|
393
|
+
const mockWebkitURL = {
|
|
394
|
+
createObjectURL: jest.fn(() => 'blob:webkit-url-67890')
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
global.window = {
|
|
398
|
+
URL: undefined,
|
|
399
|
+
webkitURL: mockWebkitURL
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
403
|
+
|
|
404
|
+
Img.setBlobToImg(mockImg, mockBlob);
|
|
405
|
+
|
|
406
|
+
expect(mockWebkitURL.createObjectURL).toHaveBeenCalledWith(mockBlob);
|
|
407
|
+
expect(mockImg.attr).toHaveBeenCalledWith('src', 'blob:webkit-url-67890');
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test('should return early and log error when img is null', () => {
|
|
411
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
412
|
+
|
|
413
|
+
Img.setBlobToImg(null, mockBlob);
|
|
414
|
+
|
|
415
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid img element provided to setBlobToImg');
|
|
416
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
417
|
+
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test('should return early and log error when img is undefined', () => {
|
|
421
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
422
|
+
|
|
423
|
+
Img.setBlobToImg(undefined, mockBlob);
|
|
424
|
+
|
|
425
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid img element provided to setBlobToImg');
|
|
426
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test('should return early and log error when img.length is 0 (empty jQuery)', () => {
|
|
430
|
+
const emptyJQuery = {
|
|
431
|
+
attr: jest.fn().mockReturnThis(),
|
|
432
|
+
length: 0 // Empty jQuery selector result
|
|
433
|
+
};
|
|
434
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
435
|
+
|
|
436
|
+
Img.setBlobToImg(emptyJQuery, mockBlob);
|
|
437
|
+
|
|
438
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid img element provided to setBlobToImg');
|
|
439
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
440
|
+
expect(emptyJQuery.attr).not.toHaveBeenCalled();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test('should return early and log error when blob is null', () => {
|
|
444
|
+
Img.setBlobToImg(mockImg, null);
|
|
445
|
+
|
|
446
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid blob provided to setBlobToImg', null);
|
|
447
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
448
|
+
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test('should return early and log error when blob is undefined', () => {
|
|
452
|
+
Img.setBlobToImg(mockImg, undefined);
|
|
453
|
+
|
|
454
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid blob provided to setBlobToImg', undefined);
|
|
455
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test('should return early and log error when blob is not a Blob instance', () => {
|
|
459
|
+
const notABlob = { data: 'test' };
|
|
460
|
+
|
|
461
|
+
Img.setBlobToImg(mockImg, notABlob);
|
|
462
|
+
|
|
463
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid blob provided to setBlobToImg', notABlob);
|
|
464
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
test('should return early and log error when blob.size is 0', () => {
|
|
468
|
+
const emptyBlob = new Blob([], { type: 'image/png' });
|
|
469
|
+
|
|
470
|
+
Img.setBlobToImg(mockImg, emptyBlob);
|
|
471
|
+
|
|
472
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid blob provided to setBlobToImg', emptyBlob);
|
|
473
|
+
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
474
|
+
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
test('should work with valid jQuery-wrapped img element with length property', () => {
|
|
478
|
+
const validJQuery = {
|
|
479
|
+
attr: jest.fn().mockReturnThis(),
|
|
480
|
+
length: 1 // Valid jQuery object
|
|
481
|
+
};
|
|
482
|
+
const mockBlob = new Blob(['test'], { type: 'image/gif' });
|
|
483
|
+
|
|
484
|
+
Img.setBlobToImg(validJQuery, mockBlob);
|
|
485
|
+
|
|
486
|
+
expect(mockURL.createObjectURL).toHaveBeenCalledWith(mockBlob);
|
|
487
|
+
expect(validJQuery.attr).toHaveBeenCalledWith('src', 'blob:mock-url-12345');
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test('should catch and log error when createObjectURL throws', () => {
|
|
491
|
+
mockURL.createObjectURL = jest.fn(() => {
|
|
492
|
+
throw new Error('Quota exceeded');
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
global.window = {
|
|
496
|
+
URL: mockURL
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
500
|
+
|
|
501
|
+
Img.setBlobToImg(mockImg, mockBlob);
|
|
502
|
+
|
|
503
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
504
|
+
'Error creating object URL from blob:',
|
|
505
|
+
expect.objectContaining({ message: 'Quota exceeded' })
|
|
506
|
+
);
|
|
507
|
+
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
test('should catch and log error when img.attr throws', () => {
|
|
511
|
+
mockImg.attr = jest.fn(() => {
|
|
512
|
+
throw new Error('Invalid element');
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
516
|
+
|
|
517
|
+
Img.setBlobToImg(mockImg, mockBlob);
|
|
518
|
+
|
|
519
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
520
|
+
'Error creating object URL from blob:',
|
|
521
|
+
expect.objectContaining({ message: 'Invalid element' })
|
|
522
|
+
);
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
describe('getBase64FromUrl', () => {
|
|
527
|
+
beforeEach(() => {
|
|
528
|
+
// Mock fetch
|
|
529
|
+
global.fetch = jest.fn(() =>
|
|
530
|
+
Promise.resolve({
|
|
531
|
+
blob: () => Promise.resolve(new Blob(['test'], { type: 'text/plain' }))
|
|
532
|
+
})
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
// Mock FileReader
|
|
536
|
+
global.FileReader = jest.fn(function() {
|
|
537
|
+
this.readAsDataURL = jest.fn(function(blob) {
|
|
538
|
+
setTimeout(() => {
|
|
539
|
+
this.result = 'data:text/plain;base64,dGVzdA==';
|
|
540
|
+
if (this.onloadend) {
|
|
541
|
+
this.onloadend();
|
|
542
|
+
}
|
|
543
|
+
}, 0);
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
test('should fetch and convert URL to base64', async () => {
|
|
549
|
+
const result = await Img.getBase64FromUrl('https://example.com/image.png');
|
|
550
|
+
|
|
551
|
+
expect(global.fetch).toHaveBeenCalledWith('https://example.com/image.png');
|
|
552
|
+
expect(result).toBe('data:text/plain;base64,dGVzdA==');
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
test('should handle different URLs', async () => {
|
|
556
|
+
const result = await Img.getBase64FromUrl('https://test.com/photo.jpg');
|
|
557
|
+
|
|
558
|
+
expect(global.fetch).toHaveBeenCalledWith('https://test.com/photo.jpg');
|
|
559
|
+
expect(result).toBeDefined();
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
test('should return a promise', () => {
|
|
563
|
+
const result = Img.getBase64FromUrl('https://example.com/image.png');
|
|
564
|
+
|
|
565
|
+
expect(result).toBeInstanceOf(Promise);
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
});
|