111 lines
4.2 KiB
TypeScript
111 lines
4.2 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { createModeControl, createMetricControl } from '../src/ui/controls';
|
|
|
|
describe('createModeControl', () => {
|
|
const modes = [
|
|
{ key: 'year', label: 'Year' },
|
|
{ key: 'week', label: 'Week' },
|
|
];
|
|
|
|
it('returns a nav element with nav-segmented class and tablist role', () => {
|
|
const nav = createModeControl('year', modes, () => {});
|
|
expect(nav.tagName).toBe('NAV');
|
|
expect(nav.className).toBe('nav nav-segmented');
|
|
expect(nav.getAttribute('role')).toBe('tablist');
|
|
});
|
|
|
|
it('renders buttons for each mode', () => {
|
|
const nav = createModeControl('year', modes, () => {});
|
|
const buttons = nav.querySelectorAll('button');
|
|
expect(buttons.length).toBe(2);
|
|
expect(buttons[0].textContent).toBe('Year');
|
|
expect(buttons[1].textContent).toBe('Week');
|
|
});
|
|
|
|
it('marks the active mode with active class and aria-selected', () => {
|
|
const nav = createModeControl('year', modes, () => {});
|
|
const buttons = nav.querySelectorAll('button');
|
|
expect(buttons[0].classList.contains('active')).toBe(true);
|
|
expect(buttons[0].getAttribute('aria-selected')).toBe('true');
|
|
expect(buttons[1].classList.contains('active')).toBe(false);
|
|
expect(buttons[1].getAttribute('aria-selected')).toBe('false');
|
|
});
|
|
|
|
it('all buttons have nav-link class and role=tab', () => {
|
|
const nav = createModeControl('year', modes, () => {});
|
|
const buttons = nav.querySelectorAll('button');
|
|
buttons.forEach((btn) => {
|
|
expect(btn.classList.contains('nav-link')).toBe(true);
|
|
expect(btn.getAttribute('role')).toBe('tab');
|
|
});
|
|
});
|
|
|
|
it('clicking inactive button updates active state and calls onChange', () => {
|
|
const onChange = vi.fn();
|
|
const nav = createModeControl('year', modes, onChange);
|
|
const buttons = nav.querySelectorAll('button');
|
|
|
|
buttons[1].click();
|
|
|
|
expect(onChange).toHaveBeenCalledWith('week');
|
|
expect(buttons[1].classList.contains('active')).toBe(true);
|
|
expect(buttons[1].getAttribute('aria-selected')).toBe('true');
|
|
expect(buttons[0].classList.contains('active')).toBe(false);
|
|
expect(buttons[0].getAttribute('aria-selected')).toBe('false');
|
|
});
|
|
|
|
it('clicking already active button still calls onChange', () => {
|
|
const onChange = vi.fn();
|
|
const nav = createModeControl('year', modes, onChange);
|
|
const buttons = nav.querySelectorAll('button');
|
|
|
|
buttons[0].click();
|
|
|
|
expect(onChange).toHaveBeenCalledWith('year');
|
|
});
|
|
});
|
|
|
|
describe('createMetricControl', () => {
|
|
it('returns a nav element with nav-segmented nav-sm classes', () => {
|
|
const nav = createMetricControl('hours', () => {});
|
|
expect(nav.tagName).toBe('NAV');
|
|
expect(nav.className).toBe('nav nav-segmented nav-sm');
|
|
expect(nav.getAttribute('role')).toBe('tablist');
|
|
});
|
|
|
|
it('renders Hours and Count buttons', () => {
|
|
const nav = createMetricControl('hours', () => {});
|
|
const buttons = nav.querySelectorAll('button');
|
|
expect(buttons.length).toBe(2);
|
|
expect(buttons[0].textContent).toBe('Hours');
|
|
expect(buttons[1].textContent).toBe('Count');
|
|
});
|
|
|
|
it('marks hours as active by default', () => {
|
|
const nav = createMetricControl('hours', () => {});
|
|
const buttons = nav.querySelectorAll('button');
|
|
expect(buttons[0].classList.contains('active')).toBe(true);
|
|
expect(buttons[1].classList.contains('active')).toBe(false);
|
|
});
|
|
|
|
it('clicking Count calls onChange with count', () => {
|
|
const onChange = vi.fn();
|
|
const nav = createMetricControl('hours', onChange);
|
|
const buttons = nav.querySelectorAll('button');
|
|
|
|
buttons[1].click();
|
|
|
|
expect(onChange).toHaveBeenCalledWith('count');
|
|
expect(buttons[1].classList.contains('active')).toBe(true);
|
|
expect(buttons[0].classList.contains('active')).toBe(false);
|
|
});
|
|
|
|
it('buttons have proper ARIA attributes', () => {
|
|
const nav = createMetricControl('count', () => {});
|
|
const buttons = nav.querySelectorAll('button');
|
|
expect(buttons[0].getAttribute('role')).toBe('tab');
|
|
expect(buttons[0].getAttribute('aria-selected')).toBe('false');
|
|
expect(buttons[1].getAttribute('role')).toBe('tab');
|
|
expect(buttons[1].getAttribute('aria-selected')).toBe('true');
|
|
});
|
|
});
|