Skip to content

Commit 436f1a1

Browse files
committed
test(chartjs): add missing tests for input, event emissions, configuration etc
1 parent 85a78cf commit 436f1a1

1 file changed

Lines changed: 303 additions & 1 deletion

File tree

projects/coreui-angular-chartjs/src/lib/chartjs.component.spec.ts

Lines changed: 303 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
1+
import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';
22

33
import { ChartjsComponent } from './chartjs.component';
44
import { Chart, registerables } from 'chart.js';
@@ -47,6 +47,15 @@ describe('ChartjsComponent', () => {
4747
fixture.detectChanges();
4848
});
4949

50+
afterEach(fakeAsync(() => {
51+
// Properly destroy chart to prevent async update errors
52+
if (component.chart) {
53+
component.chartDestroy();
54+
}
55+
flush(); // Flush all pending async operations
56+
fixture.destroy();
57+
}));
58+
5059
it('chart should create', fakeAsync(() => {
5160
expect(component).toBeTruthy();
5261
expect(component.chart).toBeDefined();
@@ -102,4 +111,297 @@ describe('ChartjsComponent', () => {
102111
fixture.detectChanges();
103112
expect(fixture.nativeElement).toHaveClass('chart-wrapper');
104113
});
114+
115+
it('should not have wrapper class when wrapper is false', () => {
116+
componentRef.setInput('wrapper', false);
117+
fixture.detectChanges();
118+
expect(fixture.nativeElement).not.toHaveClass('chart-wrapper');
119+
});
120+
121+
it('should apply height style', () => {
122+
componentRef.setInput('height', 200);
123+
fixture.detectChanges();
124+
expect(fixture.nativeElement.style.height).toBe('200px');
125+
});
126+
127+
it('should apply width style', () => {
128+
componentRef.setInput('width', 300);
129+
fixture.detectChanges();
130+
expect(fixture.nativeElement.style.width).toBe('300px');
131+
});
132+
133+
it('should generate unique IDs', () => {
134+
const fixture2 = TestBed.createComponent(ChartjsComponent);
135+
fixture2.detectChanges();
136+
expect(component.id).not.toBe(fixture2.componentInstance.id);
137+
});
138+
139+
it('should set custom ID', () => {
140+
componentRef.setInput('id', 'custom-chart-id');
141+
fixture.detectChanges();
142+
expect(component.id).toBe('custom-chart-id');
143+
});
144+
145+
it('should handle chart type changes', fakeAsync(() => {
146+
componentRef.setInput('data', { ...data });
147+
componentRef.setInput('type', 'bar');
148+
fixture.detectChanges();
149+
expect(component.type()).toBe('bar');
150+
151+
componentRef.setInput('type', 'pie');
152+
fixture.detectChanges();
153+
expect(component.type()).toBe('pie');
154+
}));
155+
156+
it('should destroy chart on component destroy', fakeAsync(() => {
157+
componentRef.setInput('data', { ...data });
158+
fixture.detectChanges();
159+
const chart = component.chart;
160+
expect(chart).toBeDefined();
161+
162+
const destroySpy = jasmine.createSpy('destroy');
163+
if (chart) {
164+
chart.destroy = destroySpy;
165+
}
166+
167+
component.ngOnDestroy();
168+
expect(destroySpy).toHaveBeenCalled();
169+
}));
170+
171+
it('should emit chartRef when chart is created', fakeAsync(() => {
172+
let emissionCount = 0;
173+
component.chartRef.subscribe(() => {
174+
emissionCount++;
175+
});
176+
componentRef.setInput('redraw', true);
177+
componentRef.setInput('data', { ...data });
178+
fixture.detectChanges();
179+
180+
expect(component.chart).toBeDefined();
181+
expect(emissionCount).toBeGreaterThan(0);
182+
}));
183+
184+
it('should handle redraw input', fakeAsync(() => {
185+
componentRef.setInput('data', { ...data });
186+
componentRef.setInput('redraw', true);
187+
fixture.detectChanges();
188+
189+
expect(component.redraw()).toBe(true);
190+
expect(component.chart).toBeDefined();
191+
}));
192+
193+
it('should emit getDatasetAtEvent on click', fakeAsync(() => {
194+
componentRef.setInput('data', { ...data });
195+
fixture.detectChanges();
196+
197+
let emittedItems: any;
198+
component.getDatasetAtEvent.subscribe((items) => {
199+
emittedItems = items;
200+
});
201+
202+
const mockEvent = new MouseEvent('click');
203+
component.handleClick(mockEvent);
204+
205+
expect(emittedItems).toBeDefined();
206+
}));
207+
208+
it('should emit getElementAtEvent on click', fakeAsync(() => {
209+
componentRef.setInput('data', { ...data });
210+
fixture.detectChanges();
211+
212+
let emittedItems: any;
213+
component.getElementAtEvent.subscribe((items) => {
214+
emittedItems = items;
215+
});
216+
217+
const mockEvent = new MouseEvent('click');
218+
component.handleClick(mockEvent);
219+
220+
expect(emittedItems).toBeDefined();
221+
}));
222+
223+
it('should emit getElementsAtEvent on click', fakeAsync(() => {
224+
componentRef.setInput('data', { ...data });
225+
fixture.detectChanges();
226+
227+
let emittedItems: any;
228+
component.getElementsAtEvent.subscribe((items) => {
229+
emittedItems = items;
230+
});
231+
232+
const mockEvent = new MouseEvent('click');
233+
component.handleClick(mockEvent);
234+
235+
expect(emittedItems).toBeDefined();
236+
}));
237+
238+
it('should not emit events when chart is not initialized', () => {
239+
// Create a fresh component without initializing the chart
240+
const newFixture = TestBed.createComponent(ChartjsComponent);
241+
const newComponent = newFixture.componentInstance;
242+
const newComponentRef = newFixture.componentRef;
243+
244+
// Don't set data to avoid chart initialization
245+
newComponentRef.setInput('type', 'line');
246+
newComponentRef.setInput('wrapper', true);
247+
newComponentRef.setInput('data', undefined);
248+
249+
let datasetEmitted = false;
250+
let elementEmitted = false;
251+
let elementsEmitted = false;
252+
253+
newComponent.getDatasetAtEvent.subscribe(() => {
254+
datasetEmitted = true;
255+
});
256+
newComponent.getElementAtEvent.subscribe(() => {
257+
elementEmitted = true;
258+
});
259+
newComponent.getElementsAtEvent.subscribe(() => {
260+
elementsEmitted = true;
261+
});
262+
263+
const mockEvent = new MouseEvent('click');
264+
newComponent.handleClick(mockEvent);
265+
266+
expect(datasetEmitted).toBeFalse();
267+
expect(elementEmitted).toBeFalse();
268+
expect(elementsEmitted).toBeFalse();
269+
});
270+
271+
it('should handle custom plugins', fakeAsync(() => {
272+
const customPlugin = {
273+
id: 'custom-plugin',
274+
beforeDraw: jasmine.createSpy('beforeDraw')
275+
};
276+
277+
componentRef.setInput('data', { ...data });
278+
componentRef.setInput('plugins', [customPlugin]);
279+
fixture.detectChanges();
280+
281+
expect(component.chart?.config.plugins).toContain(customPlugin);
282+
}));
283+
284+
it('should handle custom options', fakeAsync(() => {
285+
const customOptions = {
286+
responsive: true,
287+
maintainAspectRatio: false,
288+
scales: {
289+
x: {
290+
display: true
291+
}
292+
}
293+
};
294+
295+
componentRef.setInput('data', { ...data });
296+
componentRef.setInput('options', customOptions);
297+
fixture.detectChanges();
298+
299+
expect(component.chart?.config.options?.responsive).toBe(true);
300+
expect(component.chart?.config.options?.maintainAspectRatio).toBe(false);
301+
}));
302+
303+
it('should enable custom tooltips by default', fakeAsync(() => {
304+
componentRef.setInput('data', { ...data });
305+
fixture.detectChanges();
306+
307+
const tooltipOptions = component.chart?.config.options?.plugins?.tooltip;
308+
expect(tooltipOptions?.enabled).toBe(false);
309+
expect(tooltipOptions?.external).toBeDefined();
310+
}));
311+
312+
it('should disable custom tooltips when customTooltips is false', fakeAsync(() => {
313+
componentRef.setInput('customTooltips', false);
314+
componentRef.setInput('data', { ...data });
315+
fixture.detectChanges();
316+
317+
// When customTooltips is false, custom tooltips should not be configured
318+
// The component will still create a chart, just without custom tooltip configuration
319+
expect(component.customTooltips()).toBe(false);
320+
expect(component.chart).toBeDefined();
321+
}));
322+
323+
it('should handle empty data', fakeAsync(() => {
324+
componentRef.setInput('data', { labels: [], datasets: [] });
325+
fixture.detectChanges();
326+
327+
expect(component.chart?.config.data.labels?.length).toBe(0);
328+
expect(component.chart?.config.data.datasets.length).toBe(0);
329+
}));
330+
331+
it('should handle undefined data', () => {
332+
componentRef.setInput('data', undefined);
333+
fixture.detectChanges();
334+
expect(component.chart).toBeDefined();
335+
});
336+
337+
it('should update chart options without redraw', fakeAsync(() => {
338+
componentRef.setInput('data', { ...data });
339+
fixture.detectChanges();
340+
341+
const firstChart = component.chart;
342+
const newOptions = { responsive: false };
343+
344+
componentRef.setInput('options', newOptions);
345+
componentRef.setInput('data', { ...data });
346+
fixture.detectChanges();
347+
348+
expect(component.chart).toBe(firstChart);
349+
}));
350+
351+
it('should return base64 image string', fakeAsync(() => {
352+
componentRef.setInput('data', { ...data });
353+
componentRef.setInput('height', 100);
354+
componentRef.setInput('width', 100);
355+
fixture.detectChanges();
356+
357+
const base64 = component.chartToBase64Image();
358+
expect(base64).toBeDefined();
359+
expect(typeof base64).toBe('string');
360+
}));
361+
362+
it('should return undefined for base64 when chart is not initialized', () => {
363+
const newFixture = TestBed.createComponent(ChartjsComponent);
364+
const newComponent = newFixture.componentInstance;
365+
const newComponentRef = newFixture.componentRef;
366+
367+
newComponentRef.setInput('data', undefined);
368+
369+
const base64 = newComponent.chartToBase64Image();
370+
expect(base64).toBeUndefined();
371+
});
372+
373+
it('should handle multiple dataset updates', fakeAsync(() => {
374+
componentRef.setInput('data', { ...data });
375+
fixture.detectChanges();
376+
377+
componentRef.setInput('data', {
378+
...data,
379+
datasets: [{ ...data.datasets[0], data: [1, 2, 3] }]
380+
});
381+
fixture.detectChanges();
382+
383+
componentRef.setInput('data', {
384+
...data,
385+
datasets: [{ ...data.datasets[0], data: [4, 5, 6] }]
386+
});
387+
fixture.detectChanges();
388+
389+
expect(component.chart?.config.data.datasets[0]?.data).toEqual([4, 5, 6]);
390+
}));
391+
392+
it('should not render chart when canvas context is unavailable', () => {
393+
const newFixture = TestBed.createComponent(ChartjsComponent);
394+
const newComponent = newFixture.componentInstance;
395+
396+
spyOn(newComponent.canvasElement().nativeElement, 'getContext').and.returnValue(null);
397+
398+
newComponent.chartRender();
399+
expect(newComponent.chart).toBeUndefined();
400+
});
401+
402+
it('should not update chart when chart is not initialized', () => {
403+
const updateSpy = jasmine.createSpy('update');
404+
component.chartUpdate();
405+
expect(updateSpy).not.toHaveBeenCalled();
406+
});
105407
});

0 commit comments

Comments
 (0)