perfect-postcode/frontend/src/hooks/useTravelTime.test.ts
2026-05-15 08:17:05 +01:00

115 lines
3.3 KiB
TypeScript

import { act, renderHook } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { travelFieldKey, useTravelTime, type TravelTimeEntry } from './useTravelTime';
describe('useTravelTime', () => {
it('creates backend field keys from mode and destination slug', () => {
expect(
travelFieldKey({
mode: 'transit',
slug: 'kings-cross',
label: 'Kings Cross',
timeRange: [0, 45],
useBest: true,
})
).toBe('tt_transit_kings-cross');
});
it('adds, updates, toggles, and removes travel-time entries', () => {
const { result } = renderHook(() => useTravelTime());
act(() => result.current.handleAddEntry('transit'));
expect(result.current.entries).toEqual([
{ mode: 'transit', slug: '', label: '', timeRange: null, useBest: false },
]);
expect(result.current.activeEntries).toEqual([]);
act(() => result.current.handleSetDestination(0, 'bank', 'Bank'));
expect(result.current.entries[0]).toMatchObject({
slug: 'bank',
label: 'Bank',
timeRange: [0, 120],
});
expect(result.current.activeEntries).toHaveLength(1);
act(() => result.current.handleTimeRangeChange(0, [10, 35]));
expect(result.current.entries[0].timeRange).toEqual([10, 35]);
act(() => result.current.handleToggleBest(0));
expect(result.current.entries[0].useBest).toBe(true);
act(() => result.current.handleRemoveEntry(0));
expect(result.current.entries).toEqual([]);
});
it('replaces entries wholesale for AI-generated filters', () => {
const initial: TravelTimeEntry = {
mode: 'walking',
slug: 'old',
label: 'Old',
timeRange: [0, 20],
useBest: false,
};
const replacement: TravelTimeEntry = {
mode: 'car',
slug: 'new',
label: 'New',
timeRange: [5, 30],
useBest: false,
};
const { result } = renderHook(() => useTravelTime({ entries: [initial] }));
act(() => result.current.handleSetEntries([replacement]));
expect(result.current.entries).toEqual([replacement]);
expect(result.current.activeEntries).toEqual([replacement]);
});
it('deduplicates initial and replacement entries using the tightest range', () => {
const wide: TravelTimeEntry = {
mode: 'transit',
slug: 'bank-tube-station',
label: 'Bank',
timeRange: [0, 60],
useBest: false,
};
const tight: TravelTimeEntry = {
mode: 'transit',
slug: 'bank-tube-station',
label: 'Bank',
timeRange: [10, 45],
useBest: false,
};
const replacement: TravelTimeEntry = {
mode: 'transit',
slug: 'bank-tube-station',
label: 'Bank',
timeRange: [20, 40],
useBest: true,
};
const { result } = renderHook(() => useTravelTime({ entries: [wide, tight] }));
expect(result.current.entries).toEqual([
{
mode: 'transit',
slug: 'bank-tube-station',
label: 'Bank',
timeRange: [10, 45],
useBest: false,
},
]);
act(() => result.current.handleSetEntries([wide, replacement]));
expect(result.current.entries).toEqual([
{
mode: 'transit',
slug: 'bank-tube-station',
label: 'Bank',
timeRange: [20, 40],
useBest: true,
},
]);
});
});