Files
docs/packages/core/test/index.test.ts
zeekayandHanzo Dev 7134deb49b A page ships the page tree without its fallback, and an operation page breadcrumbs as its product
The fallback listed the 2,400 operation pages no meta lists, and every page carried it five times over: 16 GB of the 19 GB export. The browser used it only for an operation page's breadcrumb, which now comes from the product page above it.


Co-authored-by: Hanzo Dev <[email protected]>
2026-09-25 23:58:52 -07:00

284 lines
7.5 KiB
TypeScript

import { joinPath, splitPath } from '@/source/path';
import { describe, expect, test } from 'vitest';
import type { Folder, Item, Root } from '@/page-tree/definitions';
import { findNeighbour, findSiblings } from '@/page-tree/utils';
import { getBreadcrumbItems, searchNearestPath } from '@/breadcrumb';
import { DefaultFormatter } from '@/i18n/middleware';
import { NextURL } from 'next/dist/server/web/next-url';
import { updateHref } from '@/dynamic-link';
test('Find Neighbours', () => {
const tree: Root = {
name: 'Docs',
children: [
{
type: 'folder',
name: 'Custom',
children: [{ type: 'page', name: 'hello', url: '/hello' }],
},
{ type: 'page', name: 'world', url: '/world' },
{ type: 'page', name: 'user', url: '/user' },
],
};
expect(findNeighbour(tree, '/hello')).toStrictEqual({
previous: undefined,
next: { type: 'page', name: 'world', url: '/world' },
});
expect(findNeighbour(tree, '/world')).toStrictEqual({
previous: { type: 'page', name: 'hello', url: '/hello' },
next: { type: 'page', name: 'user', url: '/user' },
});
expect(findNeighbour(tree, '/user')).toStrictEqual({
previous: { type: 'page', name: 'world', url: '/world' },
next: undefined,
});
});
describe('Path utilities', () => {
test('resolve paths', () => {
expect(joinPath('a', 'b')).toBe('a/b');
expect(joinPath('/a', '')).toBe('a');
expect(joinPath('a/', '/b')).toBe('a/b');
expect(joinPath('a/', '../b/c')).toBe('b/c');
expect(joinPath('a/', './b/c')).toBe('a/b/c');
});
test('split paths', () => {
expect(splitPath('a/b/c')).toEqual(['a', 'b', 'c']);
expect(splitPath('a//c')).toEqual(['a', 'c']);
expect(splitPath('/a/c')).toEqual(['a', 'c']);
});
});
test('Breadcrumbs', () => {
const tree: Root = {
name: 'Hello World',
children: [
{
type: 'page',
name: 'Introduction',
url: '/',
},
{
type: 'page',
name: 'Hello World',
url: '/docs',
},
{
type: 'page',
name: 'Hello World',
url: '/docs/test',
},
{
type: 'page',
name: 'Hanzo Docs',
url: '/docs/test2',
},
{
type: 'folder',
name: 'Hello World',
index: {
type: 'page',
name: 'World',
url: '/docs/folder',
},
children: [],
},
],
};
expect(getBreadcrumbItems('/docs/folder', tree, { includePage: true })).toStrictEqual([
{ name: 'World', url: '/docs/folder' },
]);
expect(getBreadcrumbItems('/invalid', tree)).toMatchInlineSnapshot(`[]`);
const treeWithRoot: Root = {
name: 'Docs',
children: [
{
type: 'folder',
name: 'Docs',
root: true,
index: { type: 'page', name: 'Introduction', url: '/docs' },
children: [
{
type: 'folder',
name: 'Guides',
index: { type: 'page', name: 'Guides', url: '/docs/guides' },
children: [
{
type: 'page',
name: 'Getting Started',
url: '/docs/guides/getting-started',
},
],
},
],
},
],
};
expect(
getBreadcrumbItems('/docs/guides/getting-started', treeWithRoot, {
includeRoot: true,
includePage: true,
}),
).toStrictEqual([
{ name: 'Docs', url: '/docs' },
{ name: 'Guides', url: '/docs/guides' },
{ name: 'Getting Started', url: '/docs/guides/getting-started' },
]);
expect(
getBreadcrumbItems('/docs/guides/getting-started', treeWithRoot, {
includeRoot: false,
includePage: true,
}),
).toStrictEqual([
{ name: 'Guides', url: '/docs/guides' },
{ name: 'Getting Started', url: '/docs/guides/getting-started' },
]);
expect(
getBreadcrumbItems('/docs/guides/getting-started', treeWithRoot, {
includeRoot: { url: '/custom-root' },
includePage: true,
}),
).toStrictEqual([
{ name: 'Docs', url: '/custom-root' },
{ name: 'Guides', url: '/docs/guides' },
{ name: 'Getting Started', url: '/docs/guides/getting-started' },
]);
});
test('I18n: Format URL', () => {
expect(DefaultFormatter.get(new NextURL('https://docs.hanzo.ai/en'))).toBe('en');
expect(DefaultFormatter.get(new NextURL('https://docs.hanzo.ai/en/test'))).toBe('en');
expect(DefaultFormatter.get(new NextURL('https://docs.hanzo.ai'))).toBeUndefined();
expect(
DefaultFormatter.get(
new NextURL('https://docs.hanzo.ai/docs', {
nextConfig: {
basePath: '/docs',
},
}),
),
).toBeUndefined();
expect(
DefaultFormatter.get(
new NextURL('https://docs.hanzo.ai/docs/en/test', {
nextConfig: {
basePath: '/docs',
},
}),
),
).toBe('en');
expect(DefaultFormatter.add(new NextURL('https://docs.hanzo.ai'), 'cn').href).toBe(
'https://docs.hanzo.ai/cn/',
);
expect(
DefaultFormatter.add(
new NextURL('https://docs.hanzo.ai/docs', {
nextConfig: {
basePath: '/docs',
},
}),
'cn',
).href,
).toBe('https://docs.hanzo.ai/docs/cn/');
expect(DefaultFormatter.remove(new NextURL('https://docs.hanzo.ai/en')).href).toBe(
'https://docs.hanzo.ai/',
);
expect(DefaultFormatter.remove(new NextURL('https://docs.hanzo.ai/en/test/hello')).href).toBe(
'https://docs.hanzo.ai/test/hello',
);
expect(
DefaultFormatter.remove(
new NextURL('https://docs.hanzo.ai/docs/en', {
nextConfig: {
basePath: '/docs',
},
}),
).href,
).toBe('https://docs.hanzo.ai/docs/');
});
const tree: Root = {
name: 'docs',
children: [
{
type: 'folder',
name: 'test',
index: {
type: 'page',
name: 'Page 1',
url: '/page-1',
},
children: [
{
type: 'page',
name: 'Page 2',
url: '/page-2',
},
{
type: 'page',
name: 'Page 3',
url: '/page-3',
},
],
},
{
type: 'page',
name: 'Page 4',
url: '/page-4',
},
],
};
test('findSiblings', () => {
expect(findSiblings(tree, '/page-1')).toMatchInlineSnapshot(`
[
{
"name": "Page 2",
"type": "page",
"url": "/page-2",
},
{
"name": "Page 3",
"type": "page",
"url": "/page-3",
},
]
`);
});
test('Dynamic Link: update href', () => {
expect(updateHref('/[lang]/test', {})).toBe('/test');
expect(updateHref('/[lang]/test', { lang: 'en' })).toBe('/en/test');
expect(updateHref('/[lang]/test', { lang: ['en', 'cn'] })).toBe('/en/cn/test');
// relative -> relative
expect(updateHref('[lang]/test', {})).toBe('test');
});
// A generated reference lists a product's page and not each operation under it,
// so an operation page is placed under its product rather than nowhere.
test('Search Nearest Path', () => {
const index: Item = { type: 'page', name: 'Bot', url: '/docs/openapi/bot' };
const bot: Folder = { type: 'folder', name: 'Bot', index, children: [] };
const api: Folder = { type: 'folder', name: 'By domain', children: [bot] };
const top: Item = { type: 'page', name: 'Home', url: '/docs' };
const nodes = [top, api];
expect(searchNearestPath(nodes, '/docs/openapi/bot/get-bot-runs')).toEqual([api, bot]);
expect(searchNearestPath(nodes, '/docs/openapi/bot/get-bot-runs/')).toEqual([api, bot]);
expect(searchNearestPath(nodes, '/docs/games')).toEqual([]);
expect(searchNearestPath(nodes, '/elsewhere')).toBeNull();
});