mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-24 14:45:15 +00:00
390 lines
9.7 KiB
TypeScript
390 lines
9.7 KiB
TypeScript
import { expect, describe, it } from 'vitest'
|
|
import { generateRoutesFromFiles } from '../src/pages/utils'
|
|
import { generateRouteKey } from '../src/pages/runtime/utils'
|
|
|
|
describe('pages:generateRoutesFromFiles', () => {
|
|
const pagesDir = 'pages'
|
|
const tests = [
|
|
{
|
|
description: 'should generate correct routes for index pages',
|
|
files: [
|
|
`${pagesDir}/index.vue`,
|
|
`${pagesDir}/parent/index.vue`,
|
|
`${pagesDir}/parent/child/index.vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'index',
|
|
path: '/',
|
|
file: `${pagesDir}/index.vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'parent',
|
|
path: '/parent',
|
|
file: `${pagesDir}/parent/index.vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'parent-child',
|
|
path: '/parent/child',
|
|
file: `${pagesDir}/parent/child/index.vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct routes for parent/child',
|
|
files: [
|
|
`${pagesDir}/parent.vue`,
|
|
`${pagesDir}/parent/child.vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'parent',
|
|
path: '/parent',
|
|
file: `${pagesDir}/parent.vue`,
|
|
children: [
|
|
{
|
|
name: 'parent-child',
|
|
path: 'child',
|
|
file: `${pagesDir}/parent/child.vue`,
|
|
children: []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should not generate colliding route names when hyphens are in file name',
|
|
files: [
|
|
`${pagesDir}/parent/[child].vue`,
|
|
`${pagesDir}/parent-[child].vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'parent-child',
|
|
path: '/parent/:child',
|
|
file: `${pagesDir}/parent/[child].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'parent-child',
|
|
path: '/parent-:child',
|
|
file: `${pagesDir}/parent-[child].vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct id for catchall (order 1)',
|
|
files: [
|
|
`${pagesDir}/[...stories].vue`,
|
|
`${pagesDir}/stories/[id].vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'stories',
|
|
path: '/:stories(.*)*',
|
|
file: `${pagesDir}/[...stories].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'stories-id',
|
|
path: '/stories/:id',
|
|
file: `${pagesDir}/stories/[id].vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct id for catchall (order 2)',
|
|
files: [
|
|
`${pagesDir}/stories/[id].vue`,
|
|
`${pagesDir}/[...stories].vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'stories-id',
|
|
path: '/stories/:id',
|
|
file: `${pagesDir}/stories/[id].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'stories',
|
|
path: '/:stories(.*)*',
|
|
file: `${pagesDir}/[...stories].vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct route for snake_case file',
|
|
files: [
|
|
`${pagesDir}/snake_case.vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'snake_case',
|
|
path: '/snake_case',
|
|
file: `${pagesDir}/snake_case.vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct route for kebab-case file',
|
|
files: [`${pagesDir}/kebab-case.vue`],
|
|
output: [
|
|
{
|
|
name: 'kebab-case',
|
|
path: '/kebab-case',
|
|
file: `${pagesDir}/kebab-case.vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct dynamic routes',
|
|
files: [
|
|
`${pagesDir}/index.vue`,
|
|
`${pagesDir}/[slug].vue`,
|
|
`${pagesDir}/[[foo]]`,
|
|
`${pagesDir}/[[foo]]/index.vue`,
|
|
`${pagesDir}/[bar]/index.vue`,
|
|
`${pagesDir}/nonopt/[slug].vue`,
|
|
`${pagesDir}/opt/[[slug]].vue`,
|
|
`${pagesDir}/[[sub]]/route-[slug].vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'index',
|
|
path: '/',
|
|
file: `${pagesDir}/index.vue`,
|
|
children: []
|
|
},
|
|
{
|
|
children: [],
|
|
name: 'slug',
|
|
file: 'pages/[slug].vue',
|
|
path: '/:slug'
|
|
},
|
|
{
|
|
children: [
|
|
{
|
|
|
|
name: 'foo',
|
|
path: '',
|
|
file: `${pagesDir}/[[foo]]/index.vue`,
|
|
children: []
|
|
}
|
|
],
|
|
file: 'pages/[[foo]]',
|
|
path: '/:foo?'
|
|
},
|
|
{
|
|
children: [],
|
|
name: 'bar',
|
|
file: 'pages/[bar]/index.vue',
|
|
path: '/:bar'
|
|
},
|
|
{
|
|
name: 'nonopt-slug',
|
|
path: '/nonopt/:slug',
|
|
file: `${pagesDir}/nonopt/[slug].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'opt-slug',
|
|
path: '/opt/:slug?',
|
|
file: `${pagesDir}/opt/[[slug]].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'sub-route-slug',
|
|
path: '/:sub?/route-:slug',
|
|
file: `${pagesDir}/[[sub]]/route-[slug].vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should generate correct catch-all route',
|
|
files: [`${pagesDir}/[...slug].vue`, `${pagesDir}/index.vue`],
|
|
output: [
|
|
{
|
|
name: 'slug',
|
|
path: '/:slug(.*)*',
|
|
file: `${pagesDir}/[...slug].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'index',
|
|
path: '/',
|
|
file: `${pagesDir}/index.vue`,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
{
|
|
description: 'should throw unfinished param error for dynamic route',
|
|
files: [`${pagesDir}/[slug.vue`],
|
|
error: 'Unfinished param "slug"'
|
|
},
|
|
{
|
|
description: 'should throw empty param error for dynamic route',
|
|
files: [
|
|
`${pagesDir}/[].vue`
|
|
],
|
|
error: 'Empty param'
|
|
},
|
|
{
|
|
description: 'should only allow "_" & "." as special character for dynamic route',
|
|
files: [
|
|
`${pagesDir}/[a1_1a].vue`,
|
|
`${pagesDir}/[b2.2b].vue`,
|
|
`${pagesDir}/[[c3@3c]].vue`,
|
|
`${pagesDir}/[[d4-4d]].vue`
|
|
],
|
|
output: [
|
|
{
|
|
name: 'a1_1a',
|
|
path: '/:a1_1a',
|
|
file: `${pagesDir}/[a1_1a].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'b2.2b',
|
|
path: '/:b2.2b',
|
|
file: `${pagesDir}/[b2.2b].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'c33c',
|
|
path: '/:c33c?',
|
|
file: `${pagesDir}/[[c3@3c]].vue`,
|
|
children: []
|
|
},
|
|
{
|
|
name: 'd44d',
|
|
path: '/:d44d?',
|
|
file: `${pagesDir}/[[d4-4d]].vue`,
|
|
children: []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
|
|
for (const test of tests) {
|
|
it(test.description, async () => {
|
|
if (test.error) {
|
|
expect(() => generateRoutesFromFiles(test.files, pagesDir)).to.throws(test.error)
|
|
} else {
|
|
expect(await generateRoutesFromFiles(test.files, pagesDir)).to.deep.equal(test.output)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
describe('pages:generateRouteKey', () => {
|
|
const defaultComponent = { type: {} }
|
|
const getRouteProps = (matchedRoute = {}) => ({
|
|
Component: defaultComponent,
|
|
route: {
|
|
meta: { key: 'route-meta-key' },
|
|
params: {
|
|
id: 'foo',
|
|
optional: 'bar',
|
|
array: ['a', 'b']
|
|
},
|
|
matched: [
|
|
{
|
|
components: { default: {} },
|
|
meta: { key: 'other-meta-key' }
|
|
},
|
|
{
|
|
components: { default: defaultComponent.type },
|
|
meta: { key: 'matched-meta-key' },
|
|
...matchedRoute
|
|
}
|
|
]
|
|
}
|
|
}) as any
|
|
|
|
const tests = [
|
|
{ description: 'should handle overrides', override: 'key', route: getRouteProps(), output: 'key' },
|
|
{ description: 'should handle overrides', override: (route: any) => route.meta.key as string, route: getRouteProps(), output: 'route-meta-key' },
|
|
{ description: 'should handle overrides', override: false as any, route: getRouteProps(), output: false },
|
|
{
|
|
description: 'should key dynamic routes without keys',
|
|
route: getRouteProps({
|
|
path: '/test/:id',
|
|
meta: {}
|
|
}),
|
|
output: '/test/foo'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes without keys',
|
|
route: getRouteProps({
|
|
path: '/test/:id(\\d+)',
|
|
meta: {}
|
|
}),
|
|
output: '/test/foo'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes with optional params',
|
|
route: getRouteProps({
|
|
path: '/test/:optional?',
|
|
meta: {}
|
|
}),
|
|
output: '/test/bar'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes with optional params',
|
|
route: getRouteProps({
|
|
path: '/test/:optional(\\d+)?',
|
|
meta: {}
|
|
}),
|
|
output: '/test/bar'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes with optional params',
|
|
route: getRouteProps({
|
|
path: '/test/:undefined(\\d+)?',
|
|
meta: {}
|
|
}),
|
|
output: '/test/'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes with array params',
|
|
route: getRouteProps({
|
|
path: '/:array+',
|
|
meta: {}
|
|
}),
|
|
output: '/a,b'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes with array params',
|
|
route: getRouteProps({
|
|
path: '/test/:array*',
|
|
meta: {}
|
|
}),
|
|
output: '/test/a,b'
|
|
},
|
|
{
|
|
description: 'should key dynamic routes with array params',
|
|
route: getRouteProps({
|
|
path: '/test/:other*',
|
|
meta: {}
|
|
}),
|
|
output: '/test/'
|
|
}
|
|
]
|
|
|
|
for (const test of tests) {
|
|
it(test.description, () => {
|
|
expect(generateRouteKey(test.route, test.override)).to.deep.equal(test.output)
|
|
})
|
|
}
|
|
})
|