@osimatic/helpers-js 1.5.5 → 1.5.7
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/chartjs.js +15 -16
- package/count_down.js +30 -21
- package/details_sub_array.js +2 -0
- package/file.js +21 -18
- package/form_date.js +0 -102
- package/form_helper.js +24 -0
- package/google_charts.js +3 -0
- package/import_from_csv.js +3 -0
- package/location.js +13 -16
- package/media.js +37 -29
- package/multi_files_input.js +2 -0
- package/multiple_action_in_table.js +5 -112
- package/network.js +1 -1
- package/open_street_map.js +3 -0
- package/package.json +2 -1
- package/paging.js +4 -0
- package/select_all.js +5 -0
- package/sortable_list.js +3 -0
- package/tests/chartjs.test.js +119 -103
- package/tests/count_down.test.js +87 -201
- package/tests/file.test.js +11 -41
- package/util.js +5 -1
package/tests/count_down.test.js
CHANGED
|
@@ -4,59 +4,15 @@
|
|
|
4
4
|
const { CountDown } = require('../count_down');
|
|
5
5
|
|
|
6
6
|
describe('CountDown', () => {
|
|
7
|
-
let
|
|
8
|
-
let mockLink;
|
|
9
|
-
let mockCountDownCurrent;
|
|
10
|
-
let mockCountDownText;
|
|
7
|
+
let div;
|
|
11
8
|
let intervalCallback;
|
|
12
|
-
let clickCallback;
|
|
13
9
|
|
|
14
10
|
beforeEach(() => {
|
|
15
11
|
jest.useFakeTimers();
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
clickCallback = callback;
|
|
21
|
-
return this;
|
|
22
|
-
}),
|
|
23
|
-
attr: jest.fn().mockReturnThis(),
|
|
24
|
-
button: jest.fn().mockReturnThis(),
|
|
25
|
-
prop: jest.fn(() => false),
|
|
26
|
-
length: 1
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Mock progress bar current
|
|
30
|
-
mockCountDownCurrent = {
|
|
31
|
-
width: jest.fn(),
|
|
32
|
-
length: 1
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// Mock text element
|
|
36
|
-
mockCountDownText = {
|
|
37
|
-
html: jest.fn(),
|
|
38
|
-
length: 1
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Mock main div
|
|
42
|
-
mockDiv = {
|
|
43
|
-
length: 1,
|
|
44
|
-
append: jest.fn().mockReturnThis(),
|
|
45
|
-
find: jest.fn((selector) => {
|
|
46
|
-
if (selector === '.count_down_link a') {
|
|
47
|
-
return mockLink;
|
|
48
|
-
}
|
|
49
|
-
if (selector === '.count_down_current') {
|
|
50
|
-
return mockCountDownCurrent;
|
|
51
|
-
}
|
|
52
|
-
if (selector === '.count_down_text') {
|
|
53
|
-
return mockCountDownText;
|
|
54
|
-
}
|
|
55
|
-
return { length: 0 };
|
|
56
|
-
})
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// Spy on setInterval to capture callback
|
|
13
|
+
div = document.createElement('div');
|
|
14
|
+
document.body.appendChild(div);
|
|
15
|
+
|
|
60
16
|
const originalSetInterval = global.setInterval;
|
|
61
17
|
jest.spyOn(global, 'setInterval').mockImplementation((callback, delay) => {
|
|
62
18
|
intervalCallback = callback;
|
|
@@ -67,144 +23,124 @@ describe('CountDown', () => {
|
|
|
67
23
|
afterEach(() => {
|
|
68
24
|
jest.clearAllTimers();
|
|
69
25
|
jest.restoreAllMocks();
|
|
26
|
+
document.body.innerHTML = '';
|
|
70
27
|
});
|
|
71
28
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
29
|
+
function getLinkA() { return div.querySelector('.count_down_link a'); }
|
|
30
|
+
function getCountDownCurrent(){ return div.querySelector('.count_down_current'); }
|
|
31
|
+
function getCountDownText() { return div.querySelector('.count_down_text'); }
|
|
75
32
|
|
|
33
|
+
describe('init', () => {
|
|
34
|
+
test('should return undefined when div is null', () => {
|
|
35
|
+
const result = CountDown.init(null, { onRefreshData: jest.fn() });
|
|
76
36
|
expect(result).toBeUndefined();
|
|
77
37
|
});
|
|
78
38
|
|
|
79
39
|
test('should create countdown UI elements with provided labels', () => {
|
|
80
|
-
CountDown.init(
|
|
40
|
+
CountDown.init(div, { labelNextUpdate: 'Next Update', labelDoUpdate: 'Refresh Now' });
|
|
81
41
|
|
|
82
|
-
expect(
|
|
83
|
-
expect(
|
|
84
|
-
expect(
|
|
85
|
-
expect(
|
|
86
|
-
expect(
|
|
42
|
+
expect(div.querySelector('.count_down_title').textContent).toBe('Next Update');
|
|
43
|
+
expect(div.querySelector('.count_down_progress')).not.toBeNull();
|
|
44
|
+
expect(getCountDownCurrent()).not.toBeNull();
|
|
45
|
+
expect(getCountDownText()).not.toBeNull();
|
|
46
|
+
expect(getLinkA().textContent).toBe('Refresh Now');
|
|
87
47
|
});
|
|
88
48
|
|
|
89
49
|
test('should use default labels when not provided', () => {
|
|
90
|
-
CountDown.init(
|
|
50
|
+
CountDown.init(div, {});
|
|
91
51
|
|
|
92
|
-
expect(
|
|
93
|
-
expect(
|
|
52
|
+
expect(div.querySelector('.count_down_title').textContent).toBe('Prochaine mise à jour');
|
|
53
|
+
expect(getLinkA().textContent).toBe('Mettre à jour');
|
|
94
54
|
});
|
|
95
55
|
|
|
96
56
|
test('should set up click handler on refresh link', () => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test('should return false on click', () => {
|
|
103
|
-
const callback = jest.fn((completeCallback) => completeCallback());
|
|
104
|
-
CountDown.init(mockDiv, { onRefreshData: callback });
|
|
57
|
+
const callback = jest.fn((cb) => cb());
|
|
58
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
59
|
+
const callCountAfterInit = callback.mock.calls.length;
|
|
105
60
|
|
|
106
|
-
|
|
61
|
+
getLinkA().click();
|
|
107
62
|
|
|
108
|
-
expect(
|
|
63
|
+
expect(callback.mock.calls.length).toBeGreaterThan(callCountAfterInit);
|
|
109
64
|
});
|
|
110
65
|
|
|
111
66
|
test('should start interval timer', () => {
|
|
112
|
-
CountDown.init(
|
|
113
|
-
|
|
67
|
+
CountDown.init(div, {});
|
|
114
68
|
expect(setInterval).toHaveBeenCalledWith(expect.any(Function), 60);
|
|
115
69
|
});
|
|
116
70
|
|
|
117
71
|
test('should call onRefreshData immediately after init', () => {
|
|
118
|
-
const callback = jest.fn((
|
|
119
|
-
CountDown.init(
|
|
72
|
+
const callback = jest.fn((cb) => cb());
|
|
73
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
120
74
|
|
|
121
75
|
expect(callback).toHaveBeenCalled();
|
|
122
76
|
});
|
|
123
77
|
|
|
124
|
-
test('should
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (selector === '.count_down_text') return mockCountDownText;
|
|
129
|
-
return { length: 0 };
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
expect(() => {
|
|
133
|
-
CountDown.init(mockDiv, {});
|
|
134
|
-
}).not.toThrow();
|
|
78
|
+
test('should accept a jQuery-like object', () => {
|
|
79
|
+
const jqueryLike = { jquery: '3.6.0', 0: div, length: 1 };
|
|
80
|
+
expect(() => CountDown.init(jqueryLike, {})).not.toThrow();
|
|
81
|
+
expect(div.querySelector('.count_down_title')).not.toBeNull();
|
|
135
82
|
});
|
|
136
83
|
});
|
|
137
84
|
|
|
138
85
|
describe('refreshData', () => {
|
|
139
86
|
test('should call onRefreshData on click', () => {
|
|
140
|
-
const callback = jest.fn((
|
|
141
|
-
CountDown.init(
|
|
142
|
-
|
|
87
|
+
const callback = jest.fn((cb) => cb());
|
|
88
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
89
|
+
const callCountAfterInit = callback.mock.calls.length;
|
|
143
90
|
|
|
144
|
-
|
|
91
|
+
getLinkA().click();
|
|
145
92
|
|
|
146
|
-
expect(callback).
|
|
93
|
+
expect(callback.mock.calls.length).toBe(callCountAfterInit + 1);
|
|
147
94
|
});
|
|
148
95
|
|
|
149
96
|
test('should disable button during request', () => {
|
|
150
97
|
let callCount = 0;
|
|
151
|
-
const callback = jest.fn((
|
|
98
|
+
const callback = jest.fn((cb) => {
|
|
152
99
|
callCount++;
|
|
153
|
-
if (callCount === 1)
|
|
154
|
-
// le click ne complète pas → alreadyMakingRequest reste true
|
|
100
|
+
if (callCount === 1) cb(); // first (init) call completes, click does not
|
|
155
101
|
});
|
|
156
|
-
CountDown.init(
|
|
157
|
-
jest.clearAllMocks();
|
|
102
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
158
103
|
|
|
159
|
-
|
|
104
|
+
getLinkA().click();
|
|
160
105
|
|
|
161
|
-
expect(
|
|
162
|
-
expect(mockLink.button).toHaveBeenCalledWith('loading');
|
|
106
|
+
expect(getLinkA().disabled).toBe(true);
|
|
163
107
|
});
|
|
164
108
|
|
|
165
109
|
test('should re-enable button after request completes', () => {
|
|
166
|
-
const callback = jest.fn((
|
|
167
|
-
CountDown.init(
|
|
168
|
-
jest.clearAllMocks();
|
|
110
|
+
const callback = jest.fn((cb) => cb());
|
|
111
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
169
112
|
|
|
170
|
-
|
|
113
|
+
getLinkA().click();
|
|
171
114
|
|
|
172
|
-
expect(
|
|
173
|
-
expect(mockLink.button).toHaveBeenCalledWith('reset');
|
|
115
|
+
expect(getLinkA().disabled).toBe(false);
|
|
174
116
|
});
|
|
175
117
|
|
|
176
118
|
test('should not launch new request if already making request', () => {
|
|
177
119
|
const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
178
|
-
const callback = jest.fn(); //
|
|
179
|
-
CountDown.init(
|
|
180
|
-
|
|
181
|
-
// à ce stade le premier refreshData() a été appelé sans compléter
|
|
120
|
+
const callback = jest.fn(); // never completes → alreadyMakingRequest stays true
|
|
121
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
182
122
|
const callCountAfterInit = callback.mock.calls.length;
|
|
183
123
|
|
|
184
|
-
|
|
124
|
+
getLinkA().click();
|
|
185
125
|
|
|
186
126
|
expect(callback.mock.calls.length).toBe(callCountAfterInit);
|
|
187
127
|
expect(consoleLogSpy).toHaveBeenCalledWith('Already making request, no new request lauched.');
|
|
188
|
-
|
|
189
128
|
consoleLogSpy.mockRestore();
|
|
190
129
|
});
|
|
191
130
|
|
|
192
131
|
test('should not crash if onRefreshData is not a function', () => {
|
|
193
|
-
expect(() => {
|
|
194
|
-
CountDown.init(mockDiv, {});
|
|
195
|
-
}).not.toThrow();
|
|
132
|
+
expect(() => CountDown.init(div, {})).not.toThrow();
|
|
196
133
|
});
|
|
197
134
|
|
|
198
135
|
test('should allow new request after previous completes', () => {
|
|
199
136
|
let completeCallback;
|
|
200
137
|
const callback = jest.fn((cb) => { completeCallback = cb; });
|
|
201
|
-
CountDown.init(
|
|
138
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
202
139
|
|
|
203
|
-
// complète la première requête
|
|
204
140
|
completeCallback();
|
|
205
141
|
const callCountAfterComplete = callback.mock.calls.length;
|
|
206
142
|
|
|
207
|
-
|
|
143
|
+
getLinkA().click();
|
|
208
144
|
|
|
209
145
|
expect(callback.mock.calls.length).toBe(callCountAfterComplete + 1);
|
|
210
146
|
});
|
|
@@ -212,147 +148,97 @@ describe('CountDown', () => {
|
|
|
212
148
|
|
|
213
149
|
describe('interval timer behavior', () => {
|
|
214
150
|
test('should show remaining seconds in text', () => {
|
|
215
|
-
const callback = jest.fn((
|
|
216
|
-
CountDown.init(
|
|
217
|
-
jest.clearAllMocks();
|
|
151
|
+
const callback = jest.fn((cb) => cb());
|
|
152
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
218
153
|
|
|
219
154
|
intervalCallback();
|
|
220
155
|
|
|
221
|
-
expect(
|
|
156
|
+
expect(getCountDownText().innerHTML).toBe('10s');
|
|
222
157
|
});
|
|
223
158
|
|
|
224
159
|
test('should show 0s when time reaches limit', () => {
|
|
225
|
-
const callback = jest.fn((
|
|
226
|
-
CountDown.init(
|
|
160
|
+
const callback = jest.fn((cb) => cb());
|
|
161
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
227
162
|
|
|
228
|
-
for (let i = 0; i <
|
|
229
|
-
intervalCallback();
|
|
230
|
-
}
|
|
231
|
-
jest.clearAllMocks();
|
|
232
|
-
intervalCallback(); // tick 167 : currentMillis = 10020 → 0s
|
|
163
|
+
for (let i = 0; i < 167; i++) intervalCallback();
|
|
233
164
|
|
|
234
|
-
expect(
|
|
165
|
+
expect(getCountDownText().innerHTML).toBe('0s');
|
|
235
166
|
});
|
|
236
167
|
|
|
237
168
|
test('should set progress bar to full when time reaches limit', () => {
|
|
238
|
-
const callback = jest.fn((
|
|
239
|
-
CountDown.init(
|
|
169
|
+
const callback = jest.fn((cb) => cb());
|
|
170
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
240
171
|
|
|
241
|
-
for (let i = 0; i <
|
|
242
|
-
intervalCallback();
|
|
243
|
-
}
|
|
244
|
-
jest.clearAllMocks();
|
|
245
|
-
intervalCallback(); // tick 167 : width = 120
|
|
172
|
+
for (let i = 0; i < 167; i++) intervalCallback();
|
|
246
173
|
|
|
247
|
-
expect(
|
|
174
|
+
expect(getCountDownCurrent().style.width).toBe('120px');
|
|
248
175
|
});
|
|
249
176
|
|
|
250
|
-
test('should update progress bar width', () => {
|
|
251
|
-
const callback = jest.fn((
|
|
252
|
-
CountDown.init(
|
|
253
|
-
jest.clearAllMocks();
|
|
177
|
+
test('should update progress bar width proportionally', () => {
|
|
178
|
+
const callback = jest.fn((cb) => cb());
|
|
179
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
254
180
|
|
|
255
181
|
intervalCallback();
|
|
256
182
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
expect(
|
|
260
|
-
expect(widthArg).toBeLessThanOrEqual(120);
|
|
183
|
+
const width = parseInt(getCountDownCurrent().style.width);
|
|
184
|
+
expect(width).toBeGreaterThanOrEqual(0);
|
|
185
|
+
expect(width).toBeLessThanOrEqual(120);
|
|
261
186
|
});
|
|
262
187
|
|
|
263
188
|
test('should trigger refreshData after timeout when time limit reached', () => {
|
|
264
|
-
const callback = jest.fn((
|
|
265
|
-
CountDown.init(
|
|
189
|
+
const callback = jest.fn((cb) => cb());
|
|
190
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
266
191
|
|
|
267
|
-
for (let i = 0; i < 167; i++)
|
|
268
|
-
intervalCallback();
|
|
269
|
-
}
|
|
192
|
+
for (let i = 0; i < 167; i++) intervalCallback();
|
|
270
193
|
|
|
271
194
|
const callCountBefore = callback.mock.calls.length;
|
|
272
|
-
intervalCallback();
|
|
273
195
|
jest.advanceTimersByTime(100);
|
|
274
196
|
|
|
275
197
|
expect(callback.mock.calls.length).toBeGreaterThan(callCountBefore);
|
|
276
198
|
});
|
|
277
199
|
|
|
278
|
-
test('should reset
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const callback = jest.fn((completeCallback) => completeCallback());
|
|
282
|
-
CountDown.init(mockDiv, { onRefreshData: callback });
|
|
283
|
-
jest.clearAllMocks();
|
|
200
|
+
test('should reset currentMillis to 0 when button is disabled', () => {
|
|
201
|
+
const callback = jest.fn((cb) => cb());
|
|
202
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
284
203
|
|
|
204
|
+
getLinkA().disabled = true;
|
|
285
205
|
intervalCallback();
|
|
286
206
|
|
|
287
|
-
|
|
288
|
-
const widthArg = mockCountDownCurrent.width.mock.calls[0][0];
|
|
289
|
-
expect(widthArg).toBe(0);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
test('should handle missing progress bar element', () => {
|
|
293
|
-
mockDiv.find = jest.fn((selector) => {
|
|
294
|
-
if (selector === '.count_down_link a') return mockLink;
|
|
295
|
-
if (selector === '.count_down_current') return { length: 0 };
|
|
296
|
-
if (selector === '.count_down_text') return mockCountDownText;
|
|
297
|
-
return { length: 0 };
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
const callback = jest.fn((completeCallback) => completeCallback());
|
|
301
|
-
CountDown.init(mockDiv, { onRefreshData: callback });
|
|
302
|
-
|
|
303
|
-
expect(() => { intervalCallback(); }).not.toThrow();
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test('should handle missing text element', () => {
|
|
307
|
-
mockDiv.find = jest.fn((selector) => {
|
|
308
|
-
if (selector === '.count_down_link a') return mockLink;
|
|
309
|
-
if (selector === '.count_down_current') return mockCountDownCurrent;
|
|
310
|
-
if (selector === '.count_down_text') return { length: 0 };
|
|
311
|
-
return { length: 0 };
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
const callback = jest.fn((completeCallback) => completeCallback());
|
|
315
|
-
CountDown.init(mockDiv, { onRefreshData: callback });
|
|
316
|
-
|
|
317
|
-
expect(() => { intervalCallback(); }).not.toThrow();
|
|
207
|
+
expect(getCountDownCurrent().style.width).toBe('0px');
|
|
318
208
|
});
|
|
319
209
|
});
|
|
320
210
|
|
|
321
211
|
describe('integration scenarios', () => {
|
|
322
212
|
test('should complete full countdown cycle', () => {
|
|
323
|
-
const callback = jest.fn((
|
|
324
|
-
CountDown.init(
|
|
325
|
-
|
|
213
|
+
const callback = jest.fn((cb) => cb());
|
|
214
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
326
215
|
const initialCallCount = callback.mock.calls.length;
|
|
327
216
|
|
|
328
|
-
for (let i = 0; i < 167; i++)
|
|
329
|
-
intervalCallback();
|
|
330
|
-
}
|
|
217
|
+
for (let i = 0; i < 167; i++) intervalCallback();
|
|
331
218
|
jest.advanceTimersByTime(100);
|
|
332
219
|
|
|
333
220
|
expect(callback.mock.calls.length).toBeGreaterThan(initialCallCount);
|
|
334
221
|
});
|
|
335
222
|
|
|
336
|
-
test('should
|
|
337
|
-
const callback = jest.fn(); //
|
|
338
|
-
CountDown.init(
|
|
339
|
-
|
|
223
|
+
test('should block rapid manual refreshes when already in progress', () => {
|
|
224
|
+
const callback = jest.fn(); // never completes
|
|
225
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
340
226
|
const callCountAfterInit = callback.mock.calls.length;
|
|
341
227
|
|
|
342
|
-
|
|
343
|
-
|
|
228
|
+
getLinkA().click();
|
|
229
|
+
|
|
344
230
|
expect(callback.mock.calls.length).toBe(callCountAfterInit);
|
|
345
231
|
});
|
|
346
232
|
|
|
347
233
|
test('should allow new refresh after previous completes', () => {
|
|
348
234
|
let completeCallback;
|
|
349
235
|
const callback = jest.fn((cb) => { completeCallback = cb; });
|
|
350
|
-
CountDown.init(
|
|
236
|
+
CountDown.init(div, { onRefreshData: callback });
|
|
351
237
|
|
|
352
238
|
completeCallback();
|
|
353
239
|
const callCountAfterComplete = callback.mock.calls.length;
|
|
354
240
|
|
|
355
|
-
|
|
241
|
+
getLinkA().click();
|
|
356
242
|
expect(callback.mock.calls.length).toBe(callCountAfterComplete + 1);
|
|
357
243
|
});
|
|
358
244
|
});
|
package/tests/file.test.js
CHANGED
|
@@ -336,11 +336,7 @@ describe('Img', () => {
|
|
|
336
336
|
// Set global.Blob to our MockBlob so instanceof checks pass
|
|
337
337
|
global.Blob = MockBlob;
|
|
338
338
|
|
|
339
|
-
|
|
340
|
-
mockImg = {
|
|
341
|
-
attr: jest.fn().mockReturnThis(),
|
|
342
|
-
length: 1 // Valid jQuery object has length > 0
|
|
343
|
-
};
|
|
339
|
+
mockImg = { src: '' };
|
|
344
340
|
|
|
345
341
|
// Mock URL.createObjectURL
|
|
346
342
|
mockURL = {
|
|
@@ -377,7 +373,7 @@ describe('Img', () => {
|
|
|
377
373
|
|
|
378
374
|
Img.setBlobToImg(mockImg, mockBlob);
|
|
379
375
|
|
|
380
|
-
expect(mockImg.
|
|
376
|
+
expect(mockImg.src).toBe('blob:mock-url-12345');
|
|
381
377
|
});
|
|
382
378
|
|
|
383
379
|
test('should handle different blob types', () => {
|
|
@@ -386,7 +382,7 @@ describe('Img', () => {
|
|
|
386
382
|
Img.setBlobToImg(mockImg, mockBlob);
|
|
387
383
|
|
|
388
384
|
expect(mockURL.createObjectURL).toHaveBeenCalledWith(mockBlob);
|
|
389
|
-
expect(mockImg.
|
|
385
|
+
expect(mockImg.src).toBe('blob:mock-url-12345');
|
|
390
386
|
});
|
|
391
387
|
|
|
392
388
|
test('should use webkitURL as fallback when URL is not available', () => {
|
|
@@ -404,7 +400,7 @@ describe('Img', () => {
|
|
|
404
400
|
Img.setBlobToImg(mockImg, mockBlob);
|
|
405
401
|
|
|
406
402
|
expect(mockWebkitURL.createObjectURL).toHaveBeenCalledWith(mockBlob);
|
|
407
|
-
expect(mockImg.
|
|
403
|
+
expect(mockImg.src).toBe('blob:webkit-url-67890');
|
|
408
404
|
});
|
|
409
405
|
|
|
410
406
|
test('should return early and log error when img is null', () => {
|
|
@@ -414,7 +410,6 @@ describe('Img', () => {
|
|
|
414
410
|
|
|
415
411
|
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid img element provided to setBlobToImg');
|
|
416
412
|
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
417
|
-
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
418
413
|
});
|
|
419
414
|
|
|
420
415
|
test('should return early and log error when img is undefined', () => {
|
|
@@ -426,26 +421,12 @@ describe('Img', () => {
|
|
|
426
421
|
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
427
422
|
});
|
|
428
423
|
|
|
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
424
|
|
|
443
425
|
test('should return early and log error when blob is null', () => {
|
|
444
426
|
Img.setBlobToImg(mockImg, null);
|
|
445
427
|
|
|
446
428
|
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid blob provided to setBlobToImg', null);
|
|
447
429
|
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
448
|
-
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
449
430
|
});
|
|
450
431
|
|
|
451
432
|
test('should return early and log error when blob is undefined', () => {
|
|
@@ -471,21 +452,8 @@ describe('Img', () => {
|
|
|
471
452
|
|
|
472
453
|
expect(consoleErrorSpy).toHaveBeenCalledWith('Invalid blob provided to setBlobToImg', emptyBlob);
|
|
473
454
|
expect(mockURL.createObjectURL).not.toHaveBeenCalled();
|
|
474
|
-
expect(mockImg.attr).not.toHaveBeenCalled();
|
|
475
455
|
});
|
|
476
456
|
|
|
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
457
|
|
|
490
458
|
test('should catch and log error when createObjectURL throws', () => {
|
|
491
459
|
mockURL.createObjectURL = jest.fn(() => {
|
|
@@ -504,17 +472,19 @@ describe('Img', () => {
|
|
|
504
472
|
'Error creating object URL from blob:',
|
|
505
473
|
expect.objectContaining({ message: 'Quota exceeded' })
|
|
506
474
|
);
|
|
507
|
-
expect(mockImg.
|
|
475
|
+
expect(mockImg.src).toBe('');
|
|
508
476
|
});
|
|
509
477
|
|
|
510
|
-
test('should catch and log error when img.
|
|
511
|
-
|
|
512
|
-
|
|
478
|
+
test('should catch and log error when setting img.src throws', () => {
|
|
479
|
+
const throwingImg = {};
|
|
480
|
+
Object.defineProperty(throwingImg, 'src', {
|
|
481
|
+
set: () => { throw new Error('Invalid element'); },
|
|
482
|
+
get: () => '',
|
|
513
483
|
});
|
|
514
484
|
|
|
515
485
|
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
|
516
486
|
|
|
517
|
-
Img.setBlobToImg(
|
|
487
|
+
Img.setBlobToImg(throwingImg, mockBlob);
|
|
518
488
|
|
|
519
489
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
520
490
|
'Error creating object URL from blob:',
|