Files
solelog/apps/admin/src/screens/Live.test.tsx
Bas van Rossem 70ac27ec8e
All checks were successful
Build and Push Docker Image / build (push) Successful in 28s
style: align oxfmt to trailing-comma 'all' and normalize code
The repo was authored prettier-style (trailing-comma 'all') but .oxfmtrc.json
was set to 'es5', so every formatted file diverged. Switch the config to 'all'
to match the existing code, ignore docs/** and **/drizzle/** (prose + generated
snapshots the formatter should not own), and reformat the source tree once for
consistency. No behavioural change; all suites green (api 60, worker 28, admin 21).
2026-06-17 21:36:18 +02:00

145 lines
4.2 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { WorkSession } from '@solelog/shared';
import Live from './Live';
import { apiFetch } from '../lib/api';
vi.mock('../lib/api', () => ({
apiFetch: vi.fn(),
}));
const mockApiFetch = vi.mocked(apiFetch);
function makeSession(over: Partial<WorkSession>): WorkSession {
return {
id: 1,
user_id: 'u1',
activity_id: 10,
activity_name: 'Frezen',
user_name: 'Jan',
insole_type: 'Kurk',
pair_count: 4,
start_time: new Date(Date.now() - 65_000).toISOString(),
end_time: null,
duration_seconds: null,
paused_seconds: 0,
paused_at: null,
status: 'active',
source: 'app',
notes: null,
created_at: new Date().toISOString(),
...over,
};
}
function renderLive() {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return render(
<QueryClientProvider client={queryClient}>
<Live />
</QueryClientProvider>,
);
}
describe('Live', () => {
beforeEach(() => {
mockApiFetch.mockReset();
});
afterEach(() => {
vi.useRealTimers();
});
it('renders a card per active session with header count', async () => {
mockApiFetch.mockResolvedValue([
makeSession({ id: 1, user_name: 'Jan', activity_name: 'Frezen', insole_type: 'Kurk' }),
makeSession({ id: 2, user_name: 'Piet', activity_name: 'Lijmen', insole_type: 'Berk' }),
]);
renderLive();
expect(await screen.findByText('Actief nu (2)')).toBeInTheDocument();
expect(screen.getByText('Jan')).toBeInTheDocument();
expect(screen.getByText('Frezen')).toBeInTheDocument();
expect(screen.getByText('Piet')).toBeInTheDocument();
expect(screen.getByText('Lijmen')).toBeInTheDocument();
});
it('shows the empty state when nobody is working', async () => {
mockApiFetch.mockResolvedValue([]);
renderLive();
expect(await screen.findByText('Niemand is nu aan het werk.')).toBeInTheDocument();
expect(screen.getByText('Actief nu (0)')).toBeInTheDocument();
});
it('shows a Gepauzeerd badge with a frozen worked timer when paused_at is set', async () => {
vi.useFakeTimers();
const start = Date.now() - 100_000;
const pausedAt = Date.now() - 40_000; // paused 40s ago
mockApiFetch.mockResolvedValue([
makeSession({
id: 1,
user_name: 'Jan',
start_time: new Date(start).toISOString(),
paused_at: new Date(pausedAt).toISOString(),
paused_seconds: 10,
}),
]);
renderLive();
// The fake clock needs to advance for react-query's async resolution.
await vi.advanceTimersByTimeAsync(0);
expect(screen.getByText('Gepauzeerd')).toBeInTheDocument();
// worked = (paused_at - start)/1000 - paused_seconds = 60 - 10 = 50s = 00:00:50
const frozen = screen.getByText('00:00:50');
expect(frozen).toBeInTheDocument();
// Advance the 1s tick: the worked timer must stay frozen (does not count up).
await vi.advanceTimersByTimeAsync(3000);
expect(screen.getByText('00:00:50')).toBeInTheDocument();
});
it('shows the paused total when paused_seconds > 0', async () => {
mockApiFetch.mockResolvedValue([
makeSession({
id: 1,
user_name: 'Jan',
paused_seconds: 125,
paused_at: new Date().toISOString(),
}),
]);
renderLive();
// 125s = 00:02:05
expect(await screen.findByText('Pauze 00:02:05')).toBeInTheDocument();
});
it('keeps the timer counting (no Gepauzeerd badge) when not paused', async () => {
vi.useFakeTimers();
mockApiFetch.mockResolvedValue([
makeSession({
id: 1,
user_name: 'Jan',
start_time: new Date(Date.now() - 10_000).toISOString(),
paused_at: null,
paused_seconds: 0,
}),
]);
renderLive();
await vi.advanceTimersByTimeAsync(0);
expect(screen.queryByText('Gepauzeerd')).not.toBeInTheDocument();
expect(screen.getByText('00:00:10')).toBeInTheDocument();
await vi.advanceTimersByTimeAsync(2000);
expect(screen.getByText('00:00:12')).toBeInTheDocument();
});
});