test(overview): dedupe the MockChart test double into a shared helper

The vi.mock('chart.js', ...) MockChart class was copy-pasted verbatim
between chart-canvas.spec.ts and overview.spec.ts. Extract it to
shared/chart-canvas/testing/mock-chart.ts and import it via
vi.hoisted(async () => import(...)) in each spec, since vi.mock's
factory is hoisted above regular imports and can't reference a
plain top-level import.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Bastian Wagner
2026-08-01 20:33:22 +02:00
parent 435b8d5c53
commit 41a557f2c9
3 changed files with 40 additions and 44 deletions

View File

@@ -11,28 +11,11 @@ import { TeamStore } from '../../../core/team/team-store';
import { environment } from '../../../../environments/environment'; import { environment } from '../../../../environments/environment';
import { TeamOverviewStats } from '../../../models/team-stats.model'; import { TeamOverviewStats } from '../../../models/team-stats.model';
const { MockChart } = vi.hoisted(() => { // `vi.mock`'s factory is hoisted above regular imports, so the shared mock class is
class MockChart { // loaded via a dynamic import inside `vi.hoisted` rather than a plain top-level import.
static register = vi.fn(); const { MockChart } = await vi.hoisted(
static instances: MockChart[] = []; async () => import('../../../shared/chart-canvas/testing/mock-chart'),
data: unknown; );
options: unknown;
config: { type: unknown; data: unknown; options: unknown };
destroy = vi.fn();
update = vi.fn();
constructor(
public ctx: unknown,
config: { type: unknown; data: unknown; options: unknown },
) {
this.config = config;
this.data = config.data;
this.options = config.options;
MockChart.instances.push(this);
}
}
return { MockChart };
});
vi.mock('chart.js', () => ({ Chart: MockChart, registerables: [] })); vi.mock('chart.js', () => ({ Chart: MockChart, registerables: [] }));

View File

@@ -1,28 +1,9 @@
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { ChartCanvas } from './chart-canvas'; import { ChartCanvas } from './chart-canvas';
const { MockChart } = vi.hoisted(() => { // `vi.mock`'s factory is hoisted above regular imports, so the shared mock class is
class MockChart { // loaded via a dynamic import inside `vi.hoisted` rather than a plain top-level import.
static register = vi.fn(); const { MockChart } = await vi.hoisted(async () => import('./testing/mock-chart'));
static instances: MockChart[] = [];
data: unknown;
options: unknown;
config: { type: unknown; data: unknown; options: unknown };
destroy = vi.fn();
update = vi.fn();
constructor(
public ctx: unknown,
config: { type: unknown; data: unknown; options: unknown },
) {
this.config = config;
this.data = config.data;
this.options = config.options;
MockChart.instances.push(this);
}
}
return { MockChart };
});
vi.mock('chart.js', () => ({ Chart: MockChart, registerables: [] })); vi.mock('chart.js', () => ({ Chart: MockChart, registerables: [] }));

View File

@@ -0,0 +1,32 @@
import { vi } from 'vitest';
/**
* Test double for Chart.js's `Chart` class, shared by `chart-canvas.spec.ts` and
* `overview.spec.ts`. jsdom has no canvas 2D context, so real Chart.js cannot render
* in this project's test environment — specs mock the whole `chart.js` module via
* `vi.mock('chart.js', () => ({ Chart: MockChart, registerables: [] }))` and assert
* on the Chart.js lifecycle contract (constructor args, update(), destroy()) instead.
*
* Not a `*.spec.ts` file on purpose: it exports a class rather than defining tests,
* so it must not be picked up by the test runner's `**\/*.spec.ts` include glob.
*/
export class MockChart {
static register = vi.fn();
static instances: MockChart[] = [];
data: unknown;
options: unknown;
config: { type: unknown; data: unknown; options: unknown };
destroy = vi.fn();
update = vi.fn();
constructor(
public ctx: unknown,
config: { type: unknown; data: unknown; options: unknown },
) {
this.config = config;
this.data = config.data;
this.options = config.options;
MockChart.instances.push(this);
}
}