Files
zero-fucks-given/apps/admin/tests/unit/shared/lib/menuPath.test.ts
T

104 lines
3.3 KiB
TypeScript

import type { IntlShape } from 'react-intl';
import { describe, expect, it } from 'vitest';
import type { MenuConfig } from '#app/config/types';
import { createDevtoolsMenu } from '#devtools/config/menu';
import { createMenuPathMatcher, isMenuPathActive } from '#shared/lib/menuPath';
const intl = { formatMessage: ({ id }: { id: string }) => id } as IntlShape;
const devtoolsMenu: MenuConfig = [createDevtoolsMenu(intl)];
/** Every menu path the matcher marks active for a route — i.e. what the sidebar highlights. */
function highlighted(menu: MenuConfig, pathname: string): string[] {
const matches = createMenuPathMatcher(menu, pathname);
const active: string[] = [];
const walk = (items: MenuConfig) => {
for (const item of items) {
if (item.path && matches(item.path)) active.push(item.path);
if (item.children) walk(item.children);
}
};
walk(menu);
return active;
}
describe('isMenuPathActive', () => {
it('matches the route itself', () => {
expect(isMenuPathActive('/devtools/module-generator', '/devtools/module-generator')).toBe(true);
});
it('matches routes nested under the path', () => {
expect(isMenuPathActive('/devtools/module-generator', '/devtools/module-generator/docs')).toBe(
true
);
});
it('does not match a path that merely shares a prefix', () => {
expect(isMenuPathActive('/devtools/module-generator', '/devtools/module-generator-v2')).toBe(
false
);
});
it('ignores a trailing slash on the menu path', () => {
expect(
isMenuPathActive(
'/file-manager/tools/image-editor/-/',
'/file-manager/tools/image-editor/-/8'
)
).toBe(true);
});
it('matches the root only exactly', () => {
expect(isMenuPathActive('/', '/')).toBe(true);
expect(isMenuPathActive('/', '/devtools')).toBe(false);
});
it('is false without a path', () => {
expect(isMenuPathActive(undefined, '/devtools')).toBe(false);
});
});
describe('createMenuPathMatcher', () => {
it('highlights the section and its index item on the section route', () => {
expect(highlighted(devtoolsMenu, '/devtools/module-generator')).toEqual([
'/devtools/module-generator',
'/devtools/module-generator'
]);
});
it('highlights only the sub-page on a sub-route, not its ancestors', () => {
expect(highlighted(devtoolsMenu, '/devtools/module-generator/docs')).toEqual([
'/devtools/module-generator/docs'
]);
expect(highlighted(devtoolsMenu, '/devtools/module-generator/version')).toEqual([
'/devtools/module-generator/version'
]);
});
it('leaves a sibling section alone', () => {
expect(highlighted(devtoolsMenu, '/devtools/sandbox/ui')).toEqual(['/devtools/sandbox/ui']);
});
it('keeps the closest entry highlighted on a route with no entry of its own', () => {
const menu: MenuConfig = [
{
title: 'File manager',
children: [
{ title: 'Explorer', path: '/file-manager/drive/explorer' },
{ title: 'Settings', path: '/file-manager/drive/settings' }
]
}
];
expect(highlighted(menu, '/file-manager/drive/explorer/photos/2026')).toEqual([
'/file-manager/drive/explorer'
]);
});
it('highlights nothing when no entry matches', () => {
expect(highlighted(devtoolsMenu, '/web-studio/pages/listing')).toEqual([]);
});
});