83 lines
3.0 KiB
TypeScript
83 lines
3.0 KiB
TypeScript
import { describe, expect, test } from 'vitest';
|
|
import { createMatcher, getPathname } from './matcher';
|
|
|
|
const templates = [
|
|
'/api/websites',
|
|
'/api/websites/charts',
|
|
'/api/websites/{websiteId}',
|
|
'/api/websites/{websiteId}/replays',
|
|
'/api/websites/{websiteId}/replays/saved',
|
|
'/api/websites/{websiteId}/replays/{replayId}',
|
|
'/api/websites/{websiteId}/replays/saved/{replayId}',
|
|
'/api/websites/{websiteId}/sessions/stats',
|
|
'/api/websites/{websiteId}/sessions/weekly',
|
|
'/api/websites/{websiteId}/sessions/{sessionId}',
|
|
'/api/reports',
|
|
'/api/reports/funnel',
|
|
'/api/reports/{reportId}',
|
|
'/api/teams/join',
|
|
'/api/teams/{teamId}',
|
|
'/api/share/{slug}',
|
|
'/api/share/id/{shareId}',
|
|
];
|
|
|
|
const match = createMatcher(templates);
|
|
|
|
describe('getPathname', () => {
|
|
test('strips origin, query and hash', () => {
|
|
expect(getPathname('http://localhost:3100/api/websites?page=1#x')).toBe('/api/websites');
|
|
expect(getPathname('/api/websites?page=1')).toBe('/api/websites');
|
|
});
|
|
|
|
test('strips trailing slashes but keeps root', () => {
|
|
expect(getPathname('/api/websites/')).toBe('/api/websites');
|
|
expect(getPathname('/')).toBe('/');
|
|
});
|
|
});
|
|
|
|
describe('createMatcher', () => {
|
|
test('prefers literal segments over parameters', () => {
|
|
expect(match('/api/websites/charts')).toBe('/api/websites/charts');
|
|
expect(match('/api/websites/abc-123')).toBe('/api/websites/{websiteId}');
|
|
expect(match('/api/reports/funnel')).toBe('/api/reports/funnel');
|
|
expect(match('/api/reports/abc-123')).toBe('/api/reports/{reportId}');
|
|
expect(match('/api/teams/join')).toBe('/api/teams/join');
|
|
expect(match('/api/teams/abc-123')).toBe('/api/teams/{teamId}');
|
|
});
|
|
|
|
test('resolves nested literal/parameter ambiguity', () => {
|
|
expect(match('/api/websites/w1/replays/saved')).toBe('/api/websites/{websiteId}/replays/saved');
|
|
expect(match('/api/websites/w1/replays/r1')).toBe(
|
|
'/api/websites/{websiteId}/replays/{replayId}',
|
|
);
|
|
expect(match('/api/websites/w1/replays/saved/r1')).toBe(
|
|
'/api/websites/{websiteId}/replays/saved/{replayId}',
|
|
);
|
|
expect(match('/api/websites/w1/sessions/stats')).toBe(
|
|
'/api/websites/{websiteId}/sessions/stats',
|
|
);
|
|
expect(match('/api/websites/w1/sessions/weekly')).toBe(
|
|
'/api/websites/{websiteId}/sessions/weekly',
|
|
);
|
|
expect(match('/api/websites/w1/sessions/s1')).toBe(
|
|
'/api/websites/{websiteId}/sessions/{sessionId}',
|
|
);
|
|
});
|
|
|
|
test('distinguishes templates by segment count', () => {
|
|
expect(match('/api/share/abcdef')).toBe('/api/share/{slug}');
|
|
expect(match('/api/share/id/abcdef')).toBe('/api/share/id/{shareId}');
|
|
});
|
|
|
|
test('ignores query strings and absolute URLs', () => {
|
|
expect(match('http://localhost:3100/api/websites/w1?startAt=1&endAt=2')).toBe(
|
|
'/api/websites/{websiteId}',
|
|
);
|
|
});
|
|
|
|
test('returns null for unknown paths', () => {
|
|
expect(match('/api/nope')).toBeNull();
|
|
expect(match('/api/websites/w1/unknown')).toBeNull();
|
|
});
|
|
});
|