refactor(06-02): migrate test imports to new module locations
This commit is contained in:
parent
aab3915681
commit
881718e3f0
3 changed files with 62 additions and 21 deletions
|
|
@ -1,6 +1,20 @@
|
|||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { renderHeatmap } from '../src/heatmap';
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { YearModeRenderer } from '../src/renderers/year';
|
||||
import type { RenderContext } from '../src/renderers/types';
|
||||
import type { HeatmapData } from '../src/types';
|
||||
import { createInitialState } from '../src/state';
|
||||
|
||||
const DEFAULT_CONFIG = { cellSize: 13, cellGap: 2, marginTop: 20, marginLeft: 30, marginBottom: 4 };
|
||||
|
||||
function makeCtx(container: HTMLElement, data: HeatmapData, overrides?: Partial<RenderContext>): RenderContext {
|
||||
return {
|
||||
container,
|
||||
data,
|
||||
state: createInitialState('monday'),
|
||||
config: DEFAULT_CONFIG,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function makeMockData(overrides: Partial<HeatmapData> = {}): HeatmapData {
|
||||
return {
|
||||
|
|
@ -21,34 +35,41 @@ function makeMockData(overrides: Partial<HeatmapData> = {}): HeatmapData {
|
|||
|
||||
describe('renderHeatmap', () => {
|
||||
let container: HTMLDivElement;
|
||||
let renderer: YearModeRenderer;
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
renderer = new YearModeRenderer();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
renderer.destroy();
|
||||
document.querySelectorAll('.heatmap-tooltip').forEach(el => el.remove());
|
||||
});
|
||||
|
||||
it('renders an SVG element', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const svg = container.querySelector('svg');
|
||||
expect(svg).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders correct number of rect elements for date range', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const rects = container.querySelectorAll('rect.heatmap-cell');
|
||||
// Jan 1 to Jan 31 = 31 days
|
||||
expect(rects.length).toBe(31);
|
||||
});
|
||||
|
||||
it('applies heatmap-empty class to cells with no data', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const emptyRects = container.querySelectorAll('rect.heatmap-empty');
|
||||
// 31 days total, 5 with data = 26 empty
|
||||
expect(emptyRects.length).toBe(26);
|
||||
});
|
||||
|
||||
it('applies fill attribute to cells with data', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const allRects = container.querySelectorAll('rect.heatmap-cell:not(.heatmap-empty)');
|
||||
expect(allRects.length).toBe(5);
|
||||
allRects.forEach((rect) => {
|
||||
|
|
@ -57,7 +78,7 @@ describe('renderHeatmap', () => {
|
|||
});
|
||||
|
||||
it('renders day labels (Mon, Wed, Fri)', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const dayLabels = container.querySelectorAll('text.day-label');
|
||||
expect(dayLabels.length).toBe(7); // all 7 slots rendered
|
||||
const texts = Array.from(dayLabels).map((el) => el.textContent);
|
||||
|
|
@ -75,7 +96,7 @@ describe('renderHeatmap', () => {
|
|||
{ date: '2025-02-10', hours: 4.0, count: 1 },
|
||||
],
|
||||
});
|
||||
renderHeatmap(container, data);
|
||||
renderer.render(makeCtx(container, data));
|
||||
const monthLabels = container.querySelectorAll('text.month-label');
|
||||
expect(monthLabels.length).toBeGreaterThan(0);
|
||||
const texts = Array.from(monthLabels).map((el) => el.textContent);
|
||||
|
|
@ -83,7 +104,7 @@ describe('renderHeatmap', () => {
|
|||
});
|
||||
|
||||
it('creates tooltip on mouseenter', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const rect = container.querySelector(
|
||||
'rect.heatmap-cell:not(.heatmap-empty)',
|
||||
);
|
||||
|
|
@ -102,7 +123,7 @@ describe('renderHeatmap', () => {
|
|||
});
|
||||
|
||||
it('hides tooltip on mouseleave', () => {
|
||||
renderHeatmap(container, makeMockData());
|
||||
renderer.render(makeCtx(container, makeMockData()));
|
||||
const rect = container.querySelector(
|
||||
'rect.heatmap-cell:not(.heatmap-empty)',
|
||||
);
|
||||
|
|
@ -115,7 +136,7 @@ describe('renderHeatmap', () => {
|
|||
});
|
||||
|
||||
it('handles empty days array gracefully', () => {
|
||||
renderHeatmap(container, makeMockData({ days: [] }));
|
||||
renderer.render(makeCtx(container, makeMockData({ days: [] })));
|
||||
const svg = container.querySelector('svg');
|
||||
expect(svg).toBeNull();
|
||||
expect(container.textContent).toContain('No tracking data available');
|
||||
|
|
@ -129,7 +150,7 @@ describe('renderHeatmap', () => {
|
|||
],
|
||||
range: { begin: '2025-03-01', end: '2025-03-07' },
|
||||
};
|
||||
renderHeatmap(container, data);
|
||||
renderer.render(makeCtx(container, data));
|
||||
const rects = container.querySelectorAll('rect.heatmap-cell');
|
||||
expect(rects.length).toBe(7);
|
||||
});
|
||||
|
|
@ -142,7 +163,7 @@ describe('renderHeatmap', () => {
|
|||
],
|
||||
range: { begin: '2025-01-01', end: '2025-01-07' },
|
||||
};
|
||||
renderHeatmap(container, data);
|
||||
renderer.render(makeCtx(container, data));
|
||||
const weekendRects = container.querySelectorAll('rect.heatmap-weekend');
|
||||
// Jan 1 (Wed) through Jan 7 (Tue): Sat Jan 4 + Sun Jan 5 = 2 weekend cells
|
||||
expect(weekendRects.length).toBe(2);
|
||||
|
|
@ -155,14 +176,14 @@ describe('renderHeatmap', () => {
|
|||
],
|
||||
range: { begin: '2025-01-06', end: '2025-01-10' },
|
||||
};
|
||||
renderHeatmap(container, data);
|
||||
renderer.render(makeCtx(container, data));
|
||||
const weekendRects = container.querySelectorAll('rect.heatmap-weekend');
|
||||
// Mon-Fri, no weekends
|
||||
expect(weekendRects.length).toBe(0);
|
||||
});
|
||||
|
||||
it('renders day labels for Sunday week start', () => {
|
||||
renderHeatmap(container, makeMockData(), undefined, undefined, undefined, 'sunday');
|
||||
renderer.render(makeCtx(container, makeMockData(), { state: createInitialState('sunday') }));
|
||||
const dayLabels = container.querySelectorAll('text.day-label');
|
||||
const texts = Array.from(dayLabels).map((el) => el.textContent);
|
||||
expect(texts).toContain('Sun');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { renderHeatmap, init } from '../src/heatmap';
|
||||
import { init } from '../src/heatmap';
|
||||
import { YearModeRenderer } from '../src/renderers/year';
|
||||
import { createInitialState } from '../src/state';
|
||||
import type { HeatmapData } from '../src/types';
|
||||
|
||||
const MOCK_DATA: HeatmapData = {
|
||||
|
|
@ -10,22 +12,31 @@ const MOCK_DATA: HeatmapData = {
|
|||
range: { begin: '2025-01-01', end: '2025-01-14' },
|
||||
};
|
||||
|
||||
const DEFAULT_CONFIG = { cellSize: 13, cellGap: 2, marginTop: 20, marginLeft: 30, marginBottom: 4 };
|
||||
|
||||
describe('click navigation', () => {
|
||||
let container: HTMLDivElement;
|
||||
let renderer: YearModeRenderer;
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
renderer = new YearModeRenderer();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
renderer.destroy();
|
||||
document.querySelectorAll('.heatmap-tooltip').forEach(el => el.remove());
|
||||
document.body.removeChild(container);
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('calls onCellClick with dateStr when a data cell is clicked', () => {
|
||||
const onClick = vi.fn();
|
||||
renderHeatmap(container, MOCK_DATA, undefined, onClick);
|
||||
renderer.render({
|
||||
container, data: MOCK_DATA, state: createInitialState('monday'),
|
||||
config: DEFAULT_CONFIG, onCellClick: onClick,
|
||||
});
|
||||
const cell = container.querySelector('rect.heatmap-cell:not(.heatmap-empty)') as SVGRectElement;
|
||||
cell.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||
expect(onClick).toHaveBeenCalledOnce();
|
||||
|
|
@ -34,20 +45,29 @@ describe('click navigation', () => {
|
|||
|
||||
it('calls onCellClick when an empty cell is clicked', () => {
|
||||
const onClick = vi.fn();
|
||||
renderHeatmap(container, MOCK_DATA, undefined, onClick);
|
||||
renderer.render({
|
||||
container, data: MOCK_DATA, state: createInitialState('monday'),
|
||||
config: DEFAULT_CONFIG, onCellClick: onClick,
|
||||
});
|
||||
const emptyCell = container.querySelector('rect.heatmap-empty') as SVGRectElement;
|
||||
emptyCell.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||
expect(onClick).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('does not throw when no onCellClick provided', () => {
|
||||
renderHeatmap(container, MOCK_DATA);
|
||||
renderer.render({
|
||||
container, data: MOCK_DATA, state: createInitialState('monday'),
|
||||
config: DEFAULT_CONFIG,
|
||||
});
|
||||
const cell = container.querySelector('rect.heatmap-cell') as SVGRectElement;
|
||||
expect(() => cell.dispatchEvent(new MouseEvent('click', { bubbles: true }))).not.toThrow();
|
||||
});
|
||||
|
||||
it('all cells have heatmap-cell class for cursor styling', () => {
|
||||
renderHeatmap(container, MOCK_DATA);
|
||||
renderer.render({
|
||||
container, data: MOCK_DATA, state: createInitialState('monday'),
|
||||
config: DEFAULT_CONFIG,
|
||||
});
|
||||
const allRects = container.querySelectorAll('rect.heatmap-cell');
|
||||
expect(allRects.length).toBeGreaterThan(0);
|
||||
allRects.forEach((rect) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { timeFormat } from 'd3-time-format';
|
||||
import { timeDay } from 'd3-time';
|
||||
import { calculateStreak, calculateStats } from '../src/heatmap';
|
||||
import { calculateStreak, calculateStats } from '../src/shared/stats';
|
||||
import type { DayEntry } from '../src/types';
|
||||
|
||||
const DATE_FORMAT = timeFormat('%Y-%m-%d');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue