@osimatic/helpers-js 1.5.2 → 1.5.4

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,7 +4,6 @@
4
4
  const { GoogleCharts } = require('../google_charts');
5
5
 
6
6
  describe('GoogleCharts', () => {
7
- let mockDiv;
8
7
  let mockChart;
9
8
  let mockDataTable;
10
9
  let consoleErrorSpy;
@@ -45,42 +44,25 @@ describe('GoogleCharts', () => {
45
44
  }
46
45
  };
47
46
 
48
- // Mock jQuery
49
- mockDiv = {
50
- 0: document.createElement('div'),
51
- length: 1,
52
- removeClass: jest.fn().mockReturnThis(),
53
- addClass: jest.fn().mockReturnThis(),
54
- hasClass: jest.fn(() => false),
55
- closest: jest.fn().mockReturnThis()
56
- };
57
-
58
- global.$ = jest.fn((selector) => {
59
- if (typeof selector === 'string' && selector.startsWith('#')) {
60
- return mockDiv;
61
- }
62
- return mockDiv;
63
- });
64
-
65
- global.$.each = jest.fn((obj, callback) => {
66
- if (Array.isArray(obj)) {
67
- obj.forEach((item, idx) => callback(idx, item));
68
- } else if (typeof obj === 'object') {
69
- Object.keys(obj).forEach(key => callback(key, obj[key]));
70
- }
71
- });
72
-
73
47
  // Spy on console.error
74
48
  consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
75
49
  });
76
50
 
77
51
  afterEach(() => {
78
52
  delete global.google;
79
- delete global.$;
80
53
  consoleErrorSpy.mockRestore();
81
54
  jest.clearAllMocks();
55
+ document.body.innerHTML = '';
82
56
  });
83
57
 
58
+ function makeDiv(id, ...classes) {
59
+ const div = document.createElement('div');
60
+ div.id = id;
61
+ if (classes.length) div.classList.add(...classes);
62
+ document.body.appendChild(div);
63
+ return div;
64
+ }
65
+
84
66
  describe('init', () => {
85
67
  test('should load Google Charts with correct packages', () => {
86
68
  GoogleCharts.init();
@@ -115,14 +97,17 @@ describe('GoogleCharts', () => {
115
97
 
116
98
  describe('drawCharts', () => {
117
99
  test('should filter out charts with missing div_id', () => {
100
+ makeDiv('chart1');
101
+ makeDiv('chart2');
102
+
118
103
  const chartsList = [
119
104
  { div_id: 'chart1', chart_type: 'column_chart', title: 'Test' },
120
105
  { chart_type: 'bar_chart', title: 'No ID' },
121
106
  { div_id: 'chart2', chart_type: 'line_chart', title: 'Test 2' }
122
107
  ];
123
108
 
124
- const drawSpy = jest.spyOn(GoogleCharts, 'draw').mockImplementation((div, type, title, abscissa, absData, ordLabel, ordData, colors, format, height, width, callback) => {
125
- if (callback) callback();
109
+ const drawSpy = jest.spyOn(GoogleCharts, 'draw').mockImplementation((div, options) => {
110
+ if (options.onComplete) options.onComplete();
126
111
  });
127
112
 
128
113
  GoogleCharts.drawCharts(chartsList);
@@ -134,20 +119,16 @@ describe('GoogleCharts', () => {
134
119
  });
135
120
 
136
121
  test('should filter out charts with non-existent div elements', () => {
137
- global.$ = jest.fn((selector) => {
138
- if (selector === '#existing') {
139
- return { length: 1 };
140
- }
141
- return { length: 0 };
142
- });
122
+ makeDiv('existing');
123
+ // 'missing' is NOT added to the DOM
143
124
 
144
125
  const chartsList = [
145
126
  { div_id: 'existing', chart_type: 'column_chart', title: 'Test' },
146
127
  { div_id: 'missing', chart_type: 'bar_chart', title: 'Missing' }
147
128
  ];
148
129
 
149
- const drawSpy = jest.spyOn(GoogleCharts, 'draw').mockImplementation((div, type, title, abscissa, absData, ordLabel, ordData, colors, format, height, width, callback) => {
150
- if (callback) callback();
130
+ const drawSpy = jest.spyOn(GoogleCharts, 'draw').mockImplementation((div, options) => {
131
+ if (options.onComplete) options.onComplete();
151
132
  });
152
133
 
153
134
  GoogleCharts.drawCharts(chartsList);
@@ -158,6 +139,9 @@ describe('GoogleCharts', () => {
158
139
  });
159
140
 
160
141
  test('should call onComplete after all charts are drawn', (done) => {
142
+ makeDiv('chart1');
143
+ makeDiv('chart2');
144
+
161
145
  const chartsList = [
162
146
  {
163
147
  div_id: 'chart1',
@@ -182,10 +166,10 @@ describe('GoogleCharts', () => {
182
166
  ];
183
167
 
184
168
  const onComplete = jest.fn();
185
- const drawSpy = jest.spyOn(GoogleCharts, 'draw').mockImplementation((div, type, title, abscissa, absData, ordLabel, ordData, colors, format, height, width, callback) => {
169
+ const drawSpy = jest.spyOn(GoogleCharts, 'draw').mockImplementation((div, options) => {
186
170
  // Simulate async completion
187
171
  setTimeout(() => {
188
- if (callback) callback();
172
+ if (options.onComplete) options.onComplete();
189
173
  }, 10);
190
174
  });
191
175
 
@@ -200,6 +184,8 @@ describe('GoogleCharts', () => {
200
184
  });
201
185
 
202
186
  test('should pass all chart data to draw method', () => {
187
+ const div = makeDiv('chart1');
188
+
203
189
  const chartData = {
204
190
  div_id: 'chart1',
205
191
  chart_type: 'pie_chart',
@@ -219,18 +205,20 @@ describe('GoogleCharts', () => {
219
205
  GoogleCharts.drawCharts([chartData]);
220
206
 
221
207
  expect(drawSpy).toHaveBeenCalledWith(
222
- mockDiv,
223
- 'pie_chart',
224
- 'Test Chart',
225
- 'Category',
226
- { A: 10, B: 20 },
227
- ['Value'],
228
- [[10, 20]],
229
- ['#FF0000', '#00FF00'],
230
- '#,##0',
231
- 400,
232
- 600,
233
- expect.any(Function)
208
+ div,
209
+ expect.objectContaining({
210
+ chart_type: 'pie_chart',
211
+ title: 'Test Chart',
212
+ abscissa_label: 'Category',
213
+ abscissa_data: { A: 10, B: 20 },
214
+ ordinate_label: ['Value'],
215
+ ordinate_data: [[10, 20]],
216
+ colors: ['#FF0000', '#00FF00'],
217
+ ordinate_format: '#,##0',
218
+ height: 400,
219
+ width: 600,
220
+ onComplete: expect.any(Function),
221
+ })
234
222
  );
235
223
 
236
224
  drawSpy.mockRestore();
@@ -239,115 +227,117 @@ describe('GoogleCharts', () => {
239
227
 
240
228
  describe('draw', () => {
241
229
  test('should return early if div is undefined', () => {
242
- GoogleCharts.draw(undefined, 'column_chart', 'Title', 'X', [], ['Y'], [[]], []);
230
+ GoogleCharts.draw(undefined, { chart_type: 'column_chart', title: 'Title', abscissa_label: 'X', abscissa_data: [], ordinate_label: ['Y'], ordinate_data: [[]] });
243
231
 
244
232
  expect(consoleErrorSpy).toHaveBeenCalledWith('div not found');
245
233
  expect(mockDataTable.addColumn).not.toHaveBeenCalled();
246
234
  });
247
235
 
248
- test('should return early if div has no length', () => {
249
- const emptyDiv = { length: 0 };
250
-
251
- GoogleCharts.draw(emptyDiv, 'column_chart', 'Title', 'X', [], ['Y'], [[]], []);
236
+ test('should return early if div is null', () => {
237
+ GoogleCharts.draw(null, { chart_type: 'column_chart', title: 'Title', abscissa_label: 'X', abscissa_data: [], ordinate_label: ['Y'], ordinate_data: [[]] });
252
238
 
253
239
  expect(consoleErrorSpy).toHaveBeenCalledWith('div not found');
254
240
  });
255
241
 
256
242
  test('should create column chart', (done) => {
257
- GoogleCharts.draw(
258
- mockDiv,
259
- 'column_chart',
260
- 'Test Chart',
261
- 'Month',
262
- ['Jan', 'Feb'],
263
- ['Sales'],
264
- [[100, 200]],
265
- ['#FF0000'],
266
- null,
267
- 400,
268
- 600
269
- );
243
+ const div = makeDiv('test', 'loading');
244
+
245
+ GoogleCharts.draw(div, {
246
+ chart_type: 'column_chart',
247
+ title: 'Test Chart',
248
+ abscissa_label: 'Month',
249
+ abscissa_data: ['Jan', 'Feb'],
250
+ ordinate_label: ['Sales'],
251
+ ordinate_data: [[100, 200]],
252
+ colors: ['#FF0000'],
253
+ height: 400,
254
+ width: 600,
255
+ });
270
256
 
271
257
  setTimeout(() => {
272
- expect(global.google.charts.Bar).toHaveBeenCalledWith(mockDiv[0]);
258
+ expect(global.google.charts.Bar).toHaveBeenCalledWith(div);
273
259
  expect(mockChart.draw).toHaveBeenCalled();
274
- expect(mockDiv.removeClass).toHaveBeenCalledWith('loading');
275
- expect(mockDiv.addClass).toHaveBeenCalledWith('chart');
260
+ expect(div.classList.contains('loading')).toBe(false);
261
+ expect(div.classList.contains('chart')).toBe(true);
276
262
  done();
277
263
  }, 10);
278
264
  });
279
265
 
280
266
  test('should create bar chart', (done) => {
281
- GoogleCharts.draw(
282
- mockDiv,
283
- 'bar_chart',
284
- 'Test Chart',
285
- 'Category',
286
- ['A', 'B'],
287
- ['Value'],
288
- [[10, 20]],
289
- ['#00FF00']
290
- );
267
+ const div = makeDiv('test');
268
+
269
+ GoogleCharts.draw(div, {
270
+ chart_type: 'bar_chart',
271
+ title: 'Test Chart',
272
+ abscissa_label: 'Category',
273
+ abscissa_data: ['A', 'B'],
274
+ ordinate_label: ['Value'],
275
+ ordinate_data: [[10, 20]],
276
+ colors: ['#00FF00'],
277
+ });
291
278
 
292
279
  setTimeout(() => {
293
- expect(global.google.charts.Bar).toHaveBeenCalledWith(mockDiv[0]);
280
+ expect(global.google.charts.Bar).toHaveBeenCalledWith(div);
294
281
  expect(mockChart.draw).toHaveBeenCalled();
295
282
  done();
296
283
  }, 10);
297
284
  });
298
285
 
299
286
  test('should create line chart', (done) => {
300
- GoogleCharts.draw(
301
- mockDiv,
302
- 'line_chart',
303
- 'Test Chart',
304
- 'Time',
305
- ['1', '2'],
306
- ['Value'],
307
- [[10, 20]],
308
- ['#0000FF']
309
- );
287
+ const div = makeDiv('test');
288
+
289
+ GoogleCharts.draw(div, {
290
+ chart_type: 'line_chart',
291
+ title: 'Test Chart',
292
+ abscissa_label: 'Time',
293
+ abscissa_data: ['1', '2'],
294
+ ordinate_label: ['Value'],
295
+ ordinate_data: [[10, 20]],
296
+ colors: ['#0000FF'],
297
+ });
310
298
 
311
299
  setTimeout(() => {
312
- expect(global.google.charts.Line).toHaveBeenCalledWith(mockDiv[0]);
300
+ expect(global.google.charts.Line).toHaveBeenCalledWith(div);
313
301
  expect(mockChart.draw).toHaveBeenCalled();
314
302
  done();
315
303
  }, 10);
316
304
  });
317
305
 
318
306
  test('should create combo chart', (done) => {
319
- GoogleCharts.draw(
320
- mockDiv,
321
- 'combo_chart',
322
- 'Test Chart',
323
- 'Month',
324
- ['Jan', 'Feb'],
325
- ['Sales', 'Profit'],
326
- [[100, 200], [10, 20]],
327
- ['#FF0000', '#00FF00']
328
- );
307
+ const div = makeDiv('test');
308
+
309
+ GoogleCharts.draw(div, {
310
+ chart_type: 'combo_chart',
311
+ title: 'Test Chart',
312
+ abscissa_label: 'Month',
313
+ abscissa_data: ['Jan', 'Feb'],
314
+ ordinate_label: ['Sales', 'Profit'],
315
+ ordinate_data: [[100, 200], [10, 20]],
316
+ colors: ['#FF0000', '#00FF00'],
317
+ });
329
318
 
330
319
  setTimeout(() => {
331
- expect(global.google.visualization.ComboChart).toHaveBeenCalledWith(mockDiv[0]);
320
+ expect(global.google.visualization.ComboChart).toHaveBeenCalledWith(div);
332
321
  expect(mockChart.draw).toHaveBeenCalled();
333
322
  done();
334
323
  }, 10);
335
324
  });
336
325
 
337
326
  test('should create pie chart', (done) => {
338
- GoogleCharts.draw(
339
- mockDiv,
340
- 'pie_chart',
341
- 'Test Chart',
342
- 'Category',
343
- { A: 30, B: 50, C: 20 },
344
- [],
345
- [],
346
- ['#FF0000', '#00FF00', '#0000FF']
347
- );
327
+ const div = makeDiv('test');
328
+
329
+ GoogleCharts.draw(div, {
330
+ chart_type: 'pie_chart',
331
+ title: 'Test Chart',
332
+ abscissa_label: 'Category',
333
+ abscissa_data: { A: 30, B: 50, C: 20 },
334
+ ordinate_label: [],
335
+ ordinate_data: [],
336
+ colors: ['#FF0000', '#00FF00', '#0000FF'],
337
+ });
348
338
 
349
339
  setTimeout(() => {
350
- expect(global.google.visualization.PieChart).toHaveBeenCalledWith(mockDiv[0]);
340
+ expect(global.google.visualization.PieChart).toHaveBeenCalledWith(div);
351
341
  expect(mockDataTable.addColumn).toHaveBeenCalledWith('string', 'Category');
352
342
  expect(mockDataTable.addColumn).toHaveBeenCalledWith('number', '');
353
343
  expect(mockDataTable.addRows).toHaveBeenCalledTimes(3);
@@ -357,16 +347,17 @@ describe('GoogleCharts', () => {
357
347
  });
358
348
 
359
349
  test('should handle stacked_bar_chart type', (done) => {
360
- GoogleCharts.draw(
361
- mockDiv,
362
- 'stacked_bar_chart',
363
- 'Test Chart',
364
- 'Category',
365
- ['A', 'B'],
366
- ['Val1', 'Val2'],
367
- [[10, 20], [30, 40]],
368
- ['#FF0000', '#00FF00']
369
- );
350
+ const div = makeDiv('test');
351
+
352
+ GoogleCharts.draw(div, {
353
+ chart_type: 'stacked_bar_chart',
354
+ title: 'Test Chart',
355
+ abscissa_label: 'Category',
356
+ abscissa_data: ['A', 'B'],
357
+ ordinate_label: ['Val1', 'Val2'],
358
+ ordinate_data: [[10, 20], [30, 40]],
359
+ colors: ['#FF0000', '#00FF00'],
360
+ });
370
361
 
371
362
  setTimeout(() => {
372
363
  expect(global.google.charts.Bar).toHaveBeenCalled();
@@ -377,16 +368,17 @@ describe('GoogleCharts', () => {
377
368
  });
378
369
 
379
370
  test('should handle stacked_column_chart type', (done) => {
380
- GoogleCharts.draw(
381
- mockDiv,
382
- 'stacked_column_chart',
383
- 'Test Chart',
384
- 'Month',
385
- ['Jan', 'Feb'],
386
- ['Sales', 'Costs'],
387
- [[100, 200], [50, 80]],
388
- ['#FF0000', '#00FF00']
389
- );
371
+ const div = makeDiv('test');
372
+
373
+ GoogleCharts.draw(div, {
374
+ chart_type: 'stacked_column_chart',
375
+ title: 'Test Chart',
376
+ abscissa_label: 'Month',
377
+ abscissa_data: ['Jan', 'Feb'],
378
+ ordinate_label: ['Sales', 'Costs'],
379
+ ordinate_data: [[100, 200], [50, 80]],
380
+ colors: ['#FF0000', '#00FF00'],
381
+ });
390
382
 
391
383
  setTimeout(() => {
392
384
  expect(global.google.charts.Bar).toHaveBeenCalled();
@@ -397,16 +389,17 @@ describe('GoogleCharts', () => {
397
389
  });
398
390
 
399
391
  test('should handle stacked_combo_chart type', (done) => {
400
- GoogleCharts.draw(
401
- mockDiv,
402
- 'stacked_combo_chart',
403
- 'Test Chart',
404
- 'Month',
405
- ['Jan', 'Feb'],
406
- ['Sales', 'Costs'],
407
- [[100, 200], [50, 80]],
408
- ['#FF0000', '#00FF00']
409
- );
392
+ const div = makeDiv('test');
393
+
394
+ GoogleCharts.draw(div, {
395
+ chart_type: 'stacked_combo_chart',
396
+ title: 'Test Chart',
397
+ abscissa_label: 'Month',
398
+ abscissa_data: ['Jan', 'Feb'],
399
+ ordinate_label: ['Sales', 'Costs'],
400
+ ordinate_data: [[100, 200], [50, 80]],
401
+ colors: ['#FF0000', '#00FF00'],
402
+ });
410
403
 
411
404
  setTimeout(() => {
412
405
  expect(global.google.visualization.ComboChart).toHaveBeenCalled();
@@ -417,16 +410,17 @@ describe('GoogleCharts', () => {
417
410
  });
418
411
 
419
412
  test('should handle dual_column_chart type', (done) => {
420
- GoogleCharts.draw(
421
- mockDiv,
422
- 'dual_column_chart',
423
- 'Test Chart',
424
- 'Month',
425
- ['Jan', 'Feb'],
426
- ['Sales', 'Profit'],
427
- [[100, 200], [10, 20]],
428
- ['#FF0000', '#00FF00']
429
- );
413
+ const div = makeDiv('test');
414
+
415
+ GoogleCharts.draw(div, {
416
+ chart_type: 'dual_column_chart',
417
+ title: 'Test Chart',
418
+ abscissa_label: 'Month',
419
+ abscissa_data: ['Jan', 'Feb'],
420
+ ordinate_label: ['Sales', 'Profit'],
421
+ ordinate_data: [[100, 200], [10, 20]],
422
+ colors: ['#FF0000', '#00FF00'],
423
+ });
430
424
 
431
425
  setTimeout(() => {
432
426
  expect(global.google.charts.Bar).toHaveBeenCalled();
@@ -438,16 +432,17 @@ describe('GoogleCharts', () => {
438
432
  });
439
433
 
440
434
  test('should handle dual_bar_chart type', (done) => {
441
- GoogleCharts.draw(
442
- mockDiv,
443
- 'dual_bar_chart',
444
- 'Test Chart',
445
- 'Category',
446
- ['A', 'B'],
447
- ['Val1', 'Val2'],
448
- [[10, 20], [30, 40]],
449
- ['#FF0000', '#00FF00']
450
- );
435
+ const div = makeDiv('test');
436
+
437
+ GoogleCharts.draw(div, {
438
+ chart_type: 'dual_bar_chart',
439
+ title: 'Test Chart',
440
+ abscissa_label: 'Category',
441
+ abscissa_data: ['A', 'B'],
442
+ ordinate_label: ['Val1', 'Val2'],
443
+ ordinate_data: [[10, 20], [30, 40]],
444
+ colors: ['#FF0000', '#00FF00'],
445
+ });
451
446
 
452
447
  setTimeout(() => {
453
448
  expect(global.google.charts.Bar).toHaveBeenCalled();
@@ -459,17 +454,18 @@ describe('GoogleCharts', () => {
459
454
  });
460
455
 
461
456
  test('should apply format to vAxis when provided', (done) => {
462
- GoogleCharts.draw(
463
- mockDiv,
464
- 'column_chart',
465
- 'Test Chart',
466
- 'Month',
467
- ['Jan', 'Feb'],
468
- ['Sales'],
469
- [[100, 200]],
470
- ['#FF0000'],
471
- '#,##0.00'
472
- );
457
+ const div = makeDiv('test');
458
+
459
+ GoogleCharts.draw(div, {
460
+ chart_type: 'column_chart',
461
+ title: 'Test Chart',
462
+ abscissa_label: 'Month',
463
+ abscissa_data: ['Jan', 'Feb'],
464
+ ordinate_label: ['Sales'],
465
+ ordinate_data: [[100, 200]],
466
+ colors: ['#FF0000'],
467
+ ordinate_format: '#,##0.00',
468
+ });
473
469
 
474
470
  setTimeout(() => {
475
471
  const callArgs = mockChart.draw.mock.calls[0];
@@ -479,18 +475,18 @@ describe('GoogleCharts', () => {
479
475
  });
480
476
 
481
477
  test('should set custom height when provided', (done) => {
482
- GoogleCharts.draw(
483
- mockDiv,
484
- 'column_chart',
485
- 'Test Chart',
486
- 'Month',
487
- ['Jan', 'Feb'],
488
- ['Sales'],
489
- [[100, 200]],
490
- ['#FF0000'],
491
- null,
492
- 500
493
- );
478
+ const div = makeDiv('test');
479
+
480
+ GoogleCharts.draw(div, {
481
+ chart_type: 'column_chart',
482
+ title: 'Test Chart',
483
+ abscissa_label: 'Month',
484
+ abscissa_data: ['Jan', 'Feb'],
485
+ ordinate_label: ['Sales'],
486
+ ordinate_data: [[100, 200]],
487
+ colors: ['#FF0000'],
488
+ height: 500,
489
+ });
494
490
 
495
491
  setTimeout(() => {
496
492
  const callArgs = mockChart.draw.mock.calls[0];
@@ -500,39 +496,37 @@ describe('GoogleCharts', () => {
500
496
  });
501
497
 
502
498
  test('should handle null chart creation', () => {
503
- GoogleCharts.draw(
504
- mockDiv,
505
- 'unknown_type',
506
- 'Test Chart',
507
- 'X',
508
- ['A'],
509
- ['Y'],
510
- [[1]],
511
- ['#FF0000']
512
- );
499
+ const div = makeDiv('test');
500
+
501
+ GoogleCharts.draw(div, {
502
+ chart_type: 'unknown_type',
503
+ title: 'Test Chart',
504
+ abscissa_label: 'X',
505
+ abscissa_data: ['A'],
506
+ ordinate_label: ['Y'],
507
+ ordinate_data: [[1]],
508
+ colors: ['#FF0000'],
509
+ });
513
510
 
514
511
  expect(consoleErrorSpy).toHaveBeenCalledWith('error during creating chart');
515
- expect(mockDiv.addClass).toHaveBeenCalledWith('graphique_error');
516
- expect(mockDiv[0].innerHTML).toContain('erreur');
512
+ expect(div.classList.contains('graphique_error')).toBe(true);
513
+ expect(div.innerHTML).toContain('erreur');
517
514
  });
518
515
 
519
516
  test('should call onComplete callback when chart is ready', (done) => {
517
+ const div = makeDiv('test');
520
518
  const onComplete = jest.fn();
521
519
 
522
- GoogleCharts.draw(
523
- mockDiv,
524
- 'column_chart',
525
- 'Test Chart',
526
- 'Month',
527
- ['Jan', 'Feb'],
528
- ['Sales'],
529
- [[100, 200]],
530
- ['#FF0000'],
531
- null,
532
- null,
533
- null,
534
- onComplete
535
- );
520
+ GoogleCharts.draw(div, {
521
+ chart_type: 'column_chart',
522
+ title: 'Test Chart',
523
+ abscissa_label: 'Month',
524
+ abscissa_data: ['Jan', 'Feb'],
525
+ ordinate_label: ['Sales'],
526
+ ordinate_data: [[100, 200]],
527
+ colors: ['#FF0000'],
528
+ onComplete,
529
+ });
536
530
 
537
531
  setTimeout(() => {
538
532
  expect(onComplete).toHaveBeenCalledWith(mockChart);
@@ -541,91 +535,90 @@ describe('GoogleCharts', () => {
541
535
  });
542
536
 
543
537
  test('should handle tab-pane not active scenario', (done) => {
544
- const tabPaneDiv = {
545
- hasClass: jest.fn((className) => className === 'active' ? false : true),
546
- addClass: jest.fn().mockReturnThis(),
547
- removeClass: jest.fn().mockReturnThis()
548
- };
538
+ const tabPane = document.createElement('div');
539
+ tabPane.classList.add('tab-pane');
540
+ document.body.appendChild(tabPane);
549
541
 
550
- mockDiv.hasClass = jest.fn(() => false);
551
- mockDiv.closest = jest.fn(() => tabPaneDiv);
552
-
553
- GoogleCharts.draw(
554
- mockDiv,
555
- 'column_chart',
556
- 'Test Chart',
557
- 'Month',
558
- ['Jan'],
559
- ['Sales'],
560
- [[100]],
561
- ['#FF0000']
562
- );
542
+ const div = document.createElement('div');
543
+ tabPane.appendChild(div);
544
+
545
+ GoogleCharts.draw(div, {
546
+ chart_type: 'column_chart',
547
+ title: 'Test Chart',
548
+ abscissa_label: 'Month',
549
+ abscissa_data: ['Jan'],
550
+ ordinate_label: ['Sales'],
551
+ ordinate_data: [[100]],
552
+ colors: ['#FF0000'],
553
+ });
554
+
555
+ // tabPane.active should have been added before draw
556
+ expect(tabPane.classList.contains('active')).toBe(true);
563
557
 
564
558
  setTimeout(() => {
565
- expect(tabPaneDiv.addClass).toHaveBeenCalledWith('active');
566
- expect(tabPaneDiv.removeClass).toHaveBeenCalledWith('active');
559
+ // After ready event, active should be removed since it wasn't active before
560
+ expect(tabPane.classList.contains('active')).toBe(false);
567
561
  done();
568
562
  }, 10);
569
563
  });
570
564
 
571
565
  test('should not toggle active class if already active', (done) => {
572
- const tabPaneDiv = {
573
- hasClass: jest.fn(() => true),
574
- addClass: jest.fn().mockReturnThis(),
575
- removeClass: jest.fn().mockReturnThis()
576
- };
566
+ const tabPane = document.createElement('div');
567
+ tabPane.classList.add('tab-pane', 'active');
568
+ document.body.appendChild(tabPane);
577
569
 
578
- mockDiv.hasClass = jest.fn(() => false);
579
- mockDiv.closest = jest.fn(() => tabPaneDiv);
580
-
581
- GoogleCharts.draw(
582
- mockDiv,
583
- 'column_chart',
584
- 'Test Chart',
585
- 'Month',
586
- ['Jan'],
587
- ['Sales'],
588
- [[100]],
589
- ['#FF0000']
590
- );
570
+ const div = document.createElement('div');
571
+ tabPane.appendChild(div);
572
+
573
+ GoogleCharts.draw(div, {
574
+ chart_type: 'column_chart',
575
+ title: 'Test Chart',
576
+ abscissa_label: 'Month',
577
+ abscissa_data: ['Jan'],
578
+ ordinate_label: ['Sales'],
579
+ ordinate_data: [[100]],
580
+ colors: ['#FF0000'],
581
+ });
591
582
 
592
583
  setTimeout(() => {
593
- expect(tabPaneDiv.removeClass).not.toHaveBeenCalledWith('active');
584
+ // Still active after ready event
585
+ expect(tabPane.classList.contains('active')).toBe(true);
594
586
  done();
595
587
  }, 10);
596
588
  });
597
589
 
598
590
  test('should handle when div itself has tab-pane class', (done) => {
599
- mockDiv.hasClass = jest.fn((className) => className === 'tab-pane');
600
-
601
- GoogleCharts.draw(
602
- mockDiv,
603
- 'column_chart',
604
- 'Test Chart',
605
- 'Month',
606
- ['Jan'],
607
- ['Sales'],
608
- [[100]],
609
- ['#FF0000']
610
- );
591
+ const div = makeDiv('test', 'tab-pane');
592
+
593
+ GoogleCharts.draw(div, {
594
+ chart_type: 'column_chart',
595
+ title: 'Test Chart',
596
+ abscissa_label: 'Month',
597
+ abscissa_data: ['Jan'],
598
+ ordinate_label: ['Sales'],
599
+ ordinate_data: [[100]],
600
+ colors: ['#FF0000'],
601
+ });
611
602
 
612
603
  setTimeout(() => {
613
- expect(mockDiv.closest).not.toHaveBeenCalled();
604
+ // div itself is used as tabPaneDiv — no closest() traversal
605
+ expect(div.classList.contains('chart')).toBe(true);
614
606
  done();
615
607
  }, 10);
616
608
  });
617
609
 
618
610
  test('should set line chart specific options', (done) => {
619
- GoogleCharts.draw(
620
- mockDiv,
621
- 'line_chart',
622
- 'Test Chart',
623
- 'Time',
624
- ['1', '2'],
625
- ['Value'],
626
- [[10, 20]],
627
- ['#0000FF']
628
- );
611
+ const div = makeDiv('test');
612
+
613
+ GoogleCharts.draw(div, {
614
+ chart_type: 'line_chart',
615
+ title: 'Test Chart',
616
+ abscissa_label: 'Time',
617
+ abscissa_data: ['1', '2'],
618
+ ordinate_label: ['Value'],
619
+ ordinate_data: [[10, 20]],
620
+ colors: ['#0000FF'],
621
+ });
629
622
 
630
623
  setTimeout(() => {
631
624
  const callArgs = mockChart.draw.mock.calls[0];
@@ -636,16 +629,17 @@ describe('GoogleCharts', () => {
636
629
  });
637
630
 
638
631
  test('should set pie chart specific options', (done) => {
639
- GoogleCharts.draw(
640
- mockDiv,
641
- 'pie_chart',
642
- 'Test Chart',
643
- 'Category',
644
- { A: 30, B: 50 },
645
- [],
646
- [],
647
- ['#FF0000', '#00FF00']
648
- );
632
+ const div = makeDiv('test');
633
+
634
+ GoogleCharts.draw(div, {
635
+ chart_type: 'pie_chart',
636
+ title: 'Test Chart',
637
+ abscissa_label: 'Category',
638
+ abscissa_data: { A: 30, B: 50 },
639
+ ordinate_label: [],
640
+ ordinate_data: [],
641
+ colors: ['#FF0000', '#00FF00'],
642
+ });
649
643
 
650
644
  setTimeout(() => {
651
645
  const callArgs = mockChart.draw.mock.calls[0];
@@ -657,16 +651,17 @@ describe('GoogleCharts', () => {
657
651
  });
658
652
 
659
653
  test('should set bar chart specific options', (done) => {
660
- GoogleCharts.draw(
661
- mockDiv,
662
- 'bar_chart',
663
- 'Test Chart',
664
- 'Category',
665
- ['A', 'B'],
666
- ['Value'],
667
- [[10, 20]],
668
- ['#00FF00']
669
- );
654
+ const div = makeDiv('test');
655
+
656
+ GoogleCharts.draw(div, {
657
+ chart_type: 'bar_chart',
658
+ title: 'Test Chart',
659
+ abscissa_label: 'Category',
660
+ abscissa_data: ['A', 'B'],
661
+ ordinate_label: ['Value'],
662
+ ordinate_data: [[10, 20]],
663
+ colors: ['#00FF00'],
664
+ });
670
665
 
671
666
  setTimeout(() => {
672
667
  const callArgs = mockChart.draw.mock.calls[0];
@@ -678,16 +673,17 @@ describe('GoogleCharts', () => {
678
673
  });
679
674
 
680
675
  test('should populate DataTable correctly for non-pie charts', (done) => {
681
- GoogleCharts.draw(
682
- mockDiv,
683
- 'column_chart',
684
- 'Test Chart',
685
- 'Month',
686
- ['Jan', 'Feb', 'Mar'],
687
- ['Sales', 'Profit'],
688
- [[100, 200, 300], [10, 20, 30]],
689
- ['#FF0000', '#00FF00']
690
- );
676
+ const div = makeDiv('test');
677
+
678
+ GoogleCharts.draw(div, {
679
+ chart_type: 'column_chart',
680
+ title: 'Test Chart',
681
+ abscissa_label: 'Month',
682
+ abscissa_data: ['Jan', 'Feb', 'Mar'],
683
+ ordinate_label: ['Sales', 'Profit'],
684
+ ordinate_data: [[100, 200, 300], [10, 20, 30]],
685
+ colors: ['#FF0000', '#00FF00'],
686
+ });
691
687
 
692
688
  setTimeout(() => {
693
689
  expect(mockDataTable.addColumn).toHaveBeenCalledWith('string', 'Month');
@@ -700,16 +696,17 @@ describe('GoogleCharts', () => {
700
696
  });
701
697
 
702
698
  test('should handle combo chart with multiple series', (done) => {
703
- GoogleCharts.draw(
704
- mockDiv,
705
- 'combo_chart',
706
- 'Test Chart',
707
- 'Month',
708
- ['Jan', 'Feb'],
709
- ['Sales', 'Profit', 'Trend'],
710
- [[100, 200], [10, 20], [50, 60]],
711
- ['#FF0000', '#00FF00', '#0000FF']
712
- );
699
+ const div = makeDiv('test');
700
+
701
+ GoogleCharts.draw(div, {
702
+ chart_type: 'combo_chart',
703
+ title: 'Test Chart',
704
+ abscissa_label: 'Month',
705
+ abscissa_data: ['Jan', 'Feb'],
706
+ ordinate_label: ['Sales', 'Profit', 'Trend'],
707
+ ordinate_data: [[100, 200], [10, 20], [50, 60]],
708
+ colors: ['#FF0000', '#00FF00', '#0000FF'],
709
+ });
713
710
 
714
711
  setTimeout(() => {
715
712
  const callArgs = mockChart.draw.mock.calls[0];
@@ -722,17 +719,18 @@ describe('GoogleCharts', () => {
722
719
  });
723
720
 
724
721
  test('should apply dual axis formatting for dual_column_chart', (done) => {
725
- GoogleCharts.draw(
726
- mockDiv,
727
- 'dual_column_chart',
728
- 'Test Chart',
729
- 'Month',
730
- ['Jan', 'Feb'],
731
- ['Sales', 'Profit'],
732
- [[100, 200], [10, 20]],
733
- ['#FF0000', '#00FF00'],
734
- '$#,##0'
735
- );
722
+ const div = makeDiv('test');
723
+
724
+ GoogleCharts.draw(div, {
725
+ chart_type: 'dual_column_chart',
726
+ title: 'Test Chart',
727
+ abscissa_label: 'Month',
728
+ abscissa_data: ['Jan', 'Feb'],
729
+ ordinate_label: ['Sales', 'Profit'],
730
+ ordinate_data: [[100, 200], [10, 20]],
731
+ colors: ['#FF0000', '#00FF00'],
732
+ ordinate_format: '$#,##0',
733
+ });
736
734
 
737
735
  setTimeout(() => {
738
736
  const callArgs = mockChart.draw.mock.calls[0];
@@ -744,17 +742,18 @@ describe('GoogleCharts', () => {
744
742
  });
745
743
 
746
744
  test('should apply dual axis formatting for dual_bar_chart', (done) => {
747
- GoogleCharts.draw(
748
- mockDiv,
749
- 'dual_bar_chart',
750
- 'Test Chart',
751
- 'Category',
752
- ['A', 'B'],
753
- ['Val1', 'Val2'],
754
- [[10, 20], [30, 40]],
755
- ['#FF0000', '#00FF00'],
756
- '#,##0.00'
757
- );
745
+ const div = makeDiv('test');
746
+
747
+ GoogleCharts.draw(div, {
748
+ chart_type: 'dual_bar_chart',
749
+ title: 'Test Chart',
750
+ abscissa_label: 'Category',
751
+ abscissa_data: ['A', 'B'],
752
+ ordinate_label: ['Val1', 'Val2'],
753
+ ordinate_data: [[10, 20], [30, 40]],
754
+ colors: ['#FF0000', '#00FF00'],
755
+ ordinate_format: '#,##0.00',
756
+ });
758
757
 
759
758
  setTimeout(() => {
760
759
  const callArgs = mockChart.draw.mock.calls[0];