@osimatic/helpers-js 1.5.5 → 1.5.6

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.
@@ -4,59 +4,15 @@
4
4
  const { CountDown } = require('../count_down');
5
5
 
6
6
  describe('CountDown', () => {
7
- let mockDiv;
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
- // Mock link element
18
- mockLink = {
19
- click: jest.fn(function(callback) {
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
- describe('init', () => {
73
- test('should return undefined when div has no length', () => {
74
- const result = CountDown.init({ length: 0 }, { onRefreshData: jest.fn() });
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(mockDiv, { labelNextUpdate: 'Next Update', labelDoUpdate: 'Refresh Now' });
40
+ CountDown.init(div, { labelNextUpdate: 'Next Update', labelDoUpdate: 'Refresh Now' });
81
41
 
82
- expect(mockDiv.append).toHaveBeenCalledTimes(4);
83
- expect(mockDiv.append).toHaveBeenCalledWith('<div class="count_down_title">Next Update</div>');
84
- expect(mockDiv.append).toHaveBeenCalledWith('<div class="count_down_progress"><div class="count_down_current"></div></div>');
85
- expect(mockDiv.append).toHaveBeenCalledWith('<div class="count_down_text"></div>');
86
- expect(mockDiv.append).toHaveBeenCalledWith('<div class="count_down_link"><a href="#" data-loading-text="<i class=\'fa fa-circle-notch fa-spin\'></i>">Refresh Now</a></div>');
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(mockDiv, {});
50
+ CountDown.init(div, {});
91
51
 
92
- expect(mockDiv.append).toHaveBeenCalledWith('<div class="count_down_title">Prochaine mise à jour</div>');
93
- expect(mockDiv.append).toHaveBeenCalledWith(expect.stringContaining('Mettre à jour'));
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
- CountDown.init(mockDiv, {});
98
-
99
- expect(mockLink.click).toHaveBeenCalled();
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
- const result = clickCallback.call(mockLink);
61
+ getLinkA().click();
107
62
 
108
- expect(result).toBe(false);
63
+ expect(callback.mock.calls.length).toBeGreaterThan(callCountAfterInit);
109
64
  });
110
65
 
111
66
  test('should start interval timer', () => {
112
- CountDown.init(mockDiv, {});
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((completeCallback) => completeCallback());
119
- CountDown.init(mockDiv, { onRefreshData: callback });
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 not throw when refresh link is missing', () => {
125
- mockDiv.find = jest.fn((selector) => {
126
- if (selector === '.count_down_link a') return { length: 0, attr: jest.fn().mockReturnThis(), button: jest.fn().mockReturnThis() };
127
- if (selector === '.count_down_current') return mockCountDownCurrent;
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((completeCallback) => completeCallback());
141
- CountDown.init(mockDiv, { onRefreshData: callback });
142
- jest.clearAllMocks();
87
+ const callback = jest.fn((cb) => cb());
88
+ CountDown.init(div, { onRefreshData: callback });
89
+ const callCountAfterInit = callback.mock.calls.length;
143
90
 
144
- clickCallback.call(mockLink);
91
+ getLinkA().click();
145
92
 
146
- expect(callback).toHaveBeenCalledWith(expect.any(Function));
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((completeCallback) => {
98
+ const callback = jest.fn((cb) => {
152
99
  callCount++;
153
- if (callCount === 1) completeCallback(); // init call complète
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(mockDiv, { onRefreshData: callback });
157
- jest.clearAllMocks();
102
+ CountDown.init(div, { onRefreshData: callback });
158
103
 
159
- clickCallback.call(mockLink);
104
+ getLinkA().click();
160
105
 
161
- expect(mockLink.attr).toHaveBeenCalledWith('disabled', true);
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((completeCallback) => completeCallback());
167
- CountDown.init(mockDiv, { onRefreshData: callback });
168
- jest.clearAllMocks();
110
+ const callback = jest.fn((cb) => cb());
111
+ CountDown.init(div, { onRefreshData: callback });
169
112
 
170
- clickCallback.call(mockLink);
113
+ getLinkA().click();
171
114
 
172
- expect(mockLink.attr).toHaveBeenCalledWith('disabled', false);
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(); // ne complète pas, laisse alreadyMakingRequest = true
179
- CountDown.init(mockDiv, { onRefreshData: callback });
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
- clickCallback.call(mockLink); // bloqué
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(mockDiv, { onRefreshData: callback });
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
- clickCallback.call(mockLink);
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((completeCallback) => completeCallback());
216
- CountDown.init(mockDiv, { onRefreshData: callback });
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(mockCountDownText.html).toHaveBeenCalledWith('10s');
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((completeCallback) => completeCallback());
226
- CountDown.init(mockDiv, { onRefreshData: callback });
160
+ const callback = jest.fn((cb) => cb());
161
+ CountDown.init(div, { onRefreshData: callback });
227
162
 
228
- for (let i = 0; i < 166; 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(mockCountDownText.html).toHaveBeenCalledWith('0s');
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((completeCallback) => completeCallback());
239
- CountDown.init(mockDiv, { onRefreshData: callback });
169
+ const callback = jest.fn((cb) => cb());
170
+ CountDown.init(div, { onRefreshData: callback });
240
171
 
241
- for (let i = 0; i < 166; 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(mockCountDownCurrent.width).toHaveBeenCalledWith(120);
174
+ expect(getCountDownCurrent().style.width).toBe('120px');
248
175
  });
249
176
 
250
- test('should update progress bar width', () => {
251
- const callback = jest.fn((completeCallback) => completeCallback());
252
- CountDown.init(mockDiv, { onRefreshData: callback });
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
- expect(mockCountDownCurrent.width).toHaveBeenCalled();
258
- const widthArg = mockCountDownCurrent.width.mock.calls[0][0];
259
- expect(widthArg).toBeGreaterThanOrEqual(0);
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((completeCallback) => completeCallback());
265
- CountDown.init(mockDiv, { onRefreshData: callback });
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 progress to 0 when button is disabled', () => {
279
- mockLink.prop = jest.fn(() => true); // bouton désactivé
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
- // currentMillis reste à 0 → currentSecond = 0 → width = 0
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((completeCallback) => completeCallback());
324
- CountDown.init(mockDiv, { onRefreshData: callback });
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 handle rapid manual refreshes', () => {
337
- const callback = jest.fn(); // ne complète pas
338
- CountDown.init(mockDiv, { onRefreshData: callback });
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
- // déjà en cours → bloqué
343
- clickCallback.call(mockLink);
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(mockDiv, { onRefreshData: callback });
236
+ CountDown.init(div, { onRefreshData: callback });
351
237
 
352
238
  completeCallback();
353
239
  const callCountAfterComplete = callback.mock.calls.length;
354
240
 
355
- clickCallback.call(mockLink);
241
+ getLinkA().click();
356
242
  expect(callback.mock.calls.length).toBe(callCountAfterComplete + 1);
357
243
  });
358
244
  });
@@ -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
- // 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
- };
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.attr).toHaveBeenCalledWith('src', 'blob:mock-url-12345');
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.attr).toHaveBeenCalledWith('src', 'blob:mock-url-12345');
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.attr).toHaveBeenCalledWith('src', 'blob:webkit-url-67890');
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.attr).not.toHaveBeenCalled();
475
+ expect(mockImg.src).toBe('');
508
476
  });
509
477
 
510
- test('should catch and log error when img.attr throws', () => {
511
- mockImg.attr = jest.fn(() => {
512
- throw new Error('Invalid element');
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(mockImg, mockBlob);
487
+ Img.setBlobToImg(throwingImg, mockBlob);
518
488
 
519
489
  expect(consoleErrorSpy).toHaveBeenCalledWith(
520
490
  'Error creating object URL from blob:',
package/util.js CHANGED
@@ -14,4 +14,8 @@ function refresh() {
14
14
  window.location.reload(true);
15
15
  }
16
16
 
17
- module.exports = { sleep, refresh };
17
+ function toEl(el) {
18
+ return el && el.jquery ? el[0] : el;
19
+ }
20
+
21
+ module.exports = { sleep, refresh, toEl };