Files
electric-cherry/tests/unit/navigation-context.test.ts
T
2026-10-17 17:52:03 -04:00

80 lines
3.8 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { contextHref, returnLabel, safeReturnHref } from '../../src/lib/navigation-context.js';
describe('navigation context', () => {
it('restores Bank filters, pagination and the selected player from detail pages', () => {
const source = '/bank?view=transactions&game=t5&offset=25&player=00042&historyOffset=25';
const target = new URL(contextHref('/matches/17', source), 'http://localhost');
expect(safeReturnHref(target.searchParams.get('returnTo'), '/')).toBe(source);
expect(returnLabel(source)).toBe('Back to Bank');
});
it('restores AFK history filters and pagination after opening a player or match', () => {
const source =
'/afk?view=sessions&game=t6&server=town&state=unresolved&from=2026-10-01&offset=25';
for (const destination of ['/leaderboard/players/00042', '/matches/17']) {
const target = new URL(contextHref(destination, source), 'http://localhost');
expect(safeReturnHref(target.searchParams.get('returnTo'), '/')).toBe(source);
expect(returnLabel(source)).toBe('Back to AFK');
}
});
it('retains nested origins, list scope, loaded results and anchors', () => {
const source = new URL(
'http://localhost/leaderboard/players/42?game=t5&offset=25&returnTo=%2Fleaderboard%3Fq%3DAce#history-title'
);
const match = new URL(contextHref('/matches/123', source), source);
expect(safeReturnHref(match.searchParams.get('returnTo'), '/matches')).toBe(
source.pathname + source.search + source.hash
);
expect(returnLabel(match.searchParams.get('returnTo')!)).toBe('Back to player');
expect(returnLabel('/collections?view=history&launches=30')).toBe('Back to launch history');
});
it('retains Maintenance filters and a selected result when opening a detail', () => {
const source = '/maintenance?view=activity&state=failed&offset=25#operation-12';
const target = new URL(contextHref('/provisioning/12', source), 'http://localhost');
expect(safeReturnHref(target.searchParams.get('returnTo'), '/')).toBe(source);
expect(returnLabel(source)).toBe('Back to Maintenance');
});
it.each(['/activity', '/operations'])(
'replaces retired %s return links with their current history',
(path) => {
const source = `${path}?server=town&host=host-1&state=failed&offset=25`;
const expected = '/servers/town?tab=history&host=host-1&state=failed&offset=25';
expect(safeReturnHref(source, '/')).toBe(expected);
const target = new URL(contextHref('/provisioning/12', source), 'http://localhost');
expect(target.searchParams.get('returnTo')).toBe(expected);
expect(returnLabel(expected)).toBe('Back to server');
}
);
it('preserves the selected diagnostic tab on both sides of a contextual link', () => {
const url = new URL(
contextHref(
'/servers/t5_zombie_theater_1?tab=logs&log=console',
'/maintenance/incident?returnTo=%2Fmaintenance%3Fview%3Dactivity'
),
'http://localhost'
);
expect(url.searchParams.get('tab')).toBe('logs');
expect(url.searchParams.get('log')).toBe('console');
expect(url.searchParams.get('returnTo')).toBe(
'/maintenance/incident?returnTo=%2Fmaintenance%3Fview%3Dactivity'
);
});
it.each([
'//evil.test',
'https://evil.test/',
'/api/auth/logout',
'/login',
'/hosts/../../api/hosts',
'/\\evil.test',
'/hosts\n/42',
'/unknown',
'/' + 'x'.repeat(12000)
])('rejects unsafe or unsupported return paths: %s', (value) => {
expect(safeReturnHref(value, '/betas')).toBe('/betas');
});
});