Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

Commit

Permalink
update tests and use top to down order
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Mar 22, 2022
1 parent 82dc70d commit 9a5f14b
Show file tree
Hide file tree
Showing 20 changed files with 164 additions and 194 deletions.
3 changes: 1 addition & 2 deletions packages/nuxt3/src/pages/module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { existsSync } from 'fs'
import { defineNuxtModule, addTemplate, addPlugin, addVitePlugin, addWebpackPlugin, findPath } from '@nuxt/kit'
import { NuxtConfigSchema } from '@nuxt/schema'
import { resolve } from 'pathe'
import { genDynamicImport, genString, genArrayFromRaw, genImport, genObjectFromRawEntries } from 'knitwork'
import escapeRE from 'escape-string-regexp'
Expand All @@ -14,7 +13,7 @@ export default defineNuxtModule({
},
setup (_options, nuxt) {
const pagesDirs = nuxt.options._layers.map(
({ config }) => resolve(config.srcDir, config.dir?.pages ?? NuxtConfigSchema.dir.pages)
layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages')
)

// Disable module (and use universal router) if pages dir do not exists
Expand Down
39 changes: 20 additions & 19 deletions packages/nuxt3/src/pages/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { basename, extname, normalize, relative, resolve } from 'pathe'
import { encodePath } from 'ufo'
import { NuxtConfigSchema, NuxtMiddleware, NuxtPage } from '@nuxt/schema'
import { NuxtMiddleware, NuxtPage } from '@nuxt/schema'
import { resolveFiles, useNuxt } from '@nuxt/kit'
import { kebabCase, pascalCase } from 'scule'
import { genImport, genDynamicImport, genArrayFromRaw } from 'knitwork'
Expand All @@ -27,13 +27,8 @@ interface SegmentToken {
export async function resolvePagesRoutes (): Promise<NuxtPage[]> {
const nuxt = useNuxt()

// Page layers priority (Low to High):
// Extended Layer (1) < Extended Layer (2) < ... < Extended Layer (N-1) < Extended Layer (N) < Local layer
// Therefore, we make the local layer last
const pageLayers = [...nuxt.options._layers.slice(1), nuxt.options._layers[0]]

const pagesDirs = pageLayers.map(
({ config }) => resolve(config.srcDir, config.dir?.pages ?? NuxtConfigSchema.dir.pages)
const pagesDirs = nuxt.options._layers.map(
layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages')
)

const allRoutes = (await Promise.all(
Expand All @@ -45,8 +40,7 @@ export async function resolvePagesRoutes (): Promise<NuxtPage[]> {
})
)).flat()

// Map will returns unique routes using last duplicated route name
return [...new Map(allRoutes.map(route => [route.name, route])).values()]
return uniqueBy(allRoutes, 'name')
}

export function generateRoutesFromFiles (files: string[], pagesDir: string): NuxtPage[] {
Expand Down Expand Up @@ -252,13 +246,8 @@ export function normalizeRoutes (routes: NuxtPage[], metaImports: Set<string> =
export async function resolveMiddleware (): Promise<NuxtMiddleware[]> {
const nuxt = useNuxt()

// Route layers priority (Low to High):
// Extended Layer (1) < Extended Layer (2) < ... < Extended Layer (N-1) < Extended Layer (N) < Local layer
// Therefore, we make the local layer last
const middlewareLayers = [...nuxt.options._layers.slice(1), nuxt.options._layers[0]]

const middlewareDirs = middlewareLayers.map(
({ config }) => resolve(config.srcDir, config.dir?.middleware ?? NuxtConfigSchema.dir.middleware)
const middlewareDirs = nuxt.options._layers.map(
layer => resolve(layer.config.srcDir, layer.config.dir?.middleware || 'middleware')
)

const allMiddlewares = (await Promise.all(
Expand All @@ -268,8 +257,7 @@ export async function resolveMiddleware (): Promise<NuxtMiddleware[]> {
})
)).flat()

// Map will returns unique middlewares using last duplicated middleware name
return [...new Map(allMiddlewares.map(middleware => [middleware.name, middleware])).values()]
return uniqueBy(allMiddlewares, 'name')
}

function getNameFromPath (path: string) {
Expand All @@ -283,3 +271,16 @@ function hasSuffix (path: string, suffix: string) {
export function getImportName (name: string) {
return pascalCase(name).replace(/[^\w]/g, '')
}

function uniqueBy (arr: any[], key: string) {
const res = []
const keys = new Set<string>()
for (const item of arr) {
if (keys.has(item[key])) {
continue
}
keys.add(item[key])
res.push(item)
}
return res
}
248 changes: 136 additions & 112 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,158 +2,182 @@ import { fileURLToPath } from 'url'
import { describe, expect, it } from 'vitest'
import { setup, $fetch } from '@nuxt/test-utils'

describe('fixtures:basic', async () => {
await setup({
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
server: true
})
await setup({
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
server: true
})

describe('server api', () => {
it('should serialize', async () => {
expect(await $fetch('/api/hello')).toBe('Hello API')
expect(await $fetch('/api/hey')).toEqual({
foo: 'bar',
baz: 'qux'
})
describe('server api', () => {
it('should serialize', async () => {
expect(await $fetch('/api/hello')).toBe('Hello API')
expect(await $fetch('/api/hey')).toEqual({
foo: 'bar',
baz: 'qux'
})
})

it('should preserve states', async () => {
expect(await $fetch('/api/counter')).toEqual({ count: 0 })
expect(await $fetch('/api/counter')).toEqual({ count: 1 })
expect(await $fetch('/api/counter')).toEqual({ count: 2 })
expect(await $fetch('/api/counter')).toEqual({ count: 3 })
})
it('should preserve states', async () => {
expect(await $fetch('/api/counter')).toEqual({ count: 0 })
expect(await $fetch('/api/counter')).toEqual({ count: 1 })
expect(await $fetch('/api/counter')).toEqual({ count: 2 })
expect(await $fetch('/api/counter')).toEqual({ count: 3 })
})
})

describe('pages', () => {
it('render index', async () => {
const html = await $fetch('/')

// Snapshot
// expect(html).toMatchInlineSnapshot()

// should render text
expect(html).toContain('Hello Nuxt 3!')
// should render <Head> components
expect(html).toContain('<title>Basic fixture</title>')
// should inject runtime config
expect(html).toContain('RuntimeConfig | testConfig: 123')
// composables auto import
expect(html).toContain('Composable | foo: auto imported from ~/components/foo.ts')
expect(html).toContain('Composable | bar: auto imported from ~/components/useBar.ts')
// plugins
expect(html).toContain('Plugin | myPlugin: Injected by my-plugin')
// should import components
expect(html).toContain('This is a custom component with a named export.')
})
describe('pages', () => {
it('render index', async () => {
const html = await $fetch('/')

// Snapshot
// expect(html).toMatchInlineSnapshot()

// should render text
expect(html).toContain('Hello Nuxt 3!')
// should render <Head> components
expect(html).toContain('<title>Basic fixture</title>')
// should inject runtime config
expect(html).toContain('RuntimeConfig | testConfig: 123')
// composables auto import
expect(html).toContain('Composable | foo: auto imported from ~/components/foo.ts')
expect(html).toContain('Composable | bar: auto imported from ~/components/useBar.ts')
// plugins
expect(html).toContain('Plugin | myPlugin: Injected by my-plugin')
// should import components
expect(html).toContain('This is a custom component with a named export.')
})

it('render 404', async () => {
const html = await $fetch('/not-found')
it('render 404', async () => {
const html = await $fetch('/not-found')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('[...slug].vue')
expect(html).toContain('404 at not-found')
})
expect(html).toContain('[...slug].vue')
expect(html).toContain('404 at not-found')
})

it('/nested/[foo]/[bar].vue', async () => {
const html = await $fetch('/nested/one/two')
it('/nested/[foo]/[bar].vue', async () => {
const html = await $fetch('/nested/one/two')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('nested/[foo]/[bar].vue')
expect(html).toContain('foo: one')
expect(html).toContain('bar: two')
})
expect(html).toContain('nested/[foo]/[bar].vue')
expect(html).toContain('foo: one')
expect(html).toContain('bar: two')
})

it('/nested/[foo]/index.vue', async () => {
const html = await $fetch('/nested/foobar')
it('/nested/[foo]/index.vue', async () => {
const html = await $fetch('/nested/foobar')

// TODO: should resolved to same entry
// const html2 = await $fetch('/nested/foobar/index')
// expect(html).toEqual(html2)
// TODO: should resolved to same entry
// const html2 = await $fetch('/nested/foobar/index')
// expect(html).toEqual(html2)

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('nested/[foo]/index.vue')
expect(html).toContain('foo: foobar')
})
expect(html).toContain('nested/[foo]/index.vue')
expect(html).toContain('foo: foobar')
})

it('/nested/[foo]/user-[group].vue', async () => {
const html = await $fetch('/nested/foobar/user-admin')
it('/nested/[foo]/user-[group].vue', async () => {
const html = await $fetch('/nested/foobar/user-admin')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('nested/[foo]/user-[group].vue')
expect(html).toContain('foo: foobar')
expect(html).toContain('group: admin')
})
expect(html).toContain('nested/[foo]/user-[group].vue')
expect(html).toContain('foo: foobar')
expect(html).toContain('group: admin')
})
})

describe('navigate', () => {
it('should redirect to index with navigateTo', async () => {
const html = await $fetch('/navigate-to/')
describe('navigate', () => {
it('should redirect to index with navigateTo', async () => {
const html = await $fetch('/navigate-to/')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('Hello Nuxt 3!')
})
expect(html).toContain('Hello Nuxt 3!')
})
})

describe('middlewares', () => {
it('should redirect to index with global middleware', async () => {
const html = await $fetch('/redirect/')
describe('middlewares', () => {
it('should redirect to index with global middleware', async () => {
const html = await $fetch('/redirect/')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('Hello Nuxt 3!')
})
expect(html).toContain('Hello Nuxt 3!')
})

it('should inject auth', async () => {
const html = await $fetch('/auth')
it('should inject auth', async () => {
const html = await $fetch('/auth')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('auth.vue')
expect(html).toContain('auth: Injected by injectAuth middleware')
})
expect(html).toContain('auth.vue')
expect(html).toContain('auth: Injected by injectAuth middleware')
})

it('should not inject auth', async () => {
const html = await $fetch('/no-auth')
it('should not inject auth', async () => {
const html = await $fetch('/no-auth')

// Snapshot
// expect(html).toMatchInlineSnapshot()
// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('no-auth.vue')
expect(html).toContain('auth: ')
expect(html).not.toContain('Injected by injectAuth middleware')
})
expect(html).toContain('no-auth.vue')
expect(html).toContain('auth: ')
expect(html).not.toContain('Injected by injectAuth middleware')
})
})

describe('layouts', () => {
it('should apply custom layout', async () => {
const html = await $fetch('/with-layout')

// Snapshot
// expect(html).toMatchInlineSnapshot()

expect(html).toContain('with-layout.vue')
expect(html).toContain('Custom Layout:')
})
})

describe('layouts', () => {
it('should apply custom layout', async () => {
const html = await $fetch('/with-layout')
describe('reactivity transform', () => {
it('should works', async () => {
const html = await $fetch('/')

// Snapshot
// expect(html).toMatchInlineSnapshot()
expect(html).toContain('Sugar Counter 12 x 2 = 24')
})
})

expect(html).toContain('with-layout.vue')
expect(html).toContain('Custom Layout:')
describe('extends support', () => {
describe('pages', () => {
it('extends foo/pages/index.vue', async () => {
const html = await $fetch('/foo')
expect(html).toContain('Hello from extended page of foo!')
})

it('extends bar/pages/override.vue over foo/pages/override.vue', async () => {
const html = await $fetch('/override')
expect(html).toContain('Extended page from bar')
})
})

describe('reactivity transform', () => {
it('should works', async () => {
const html = await $fetch('/')
describe('middlewares', () => {
it('extends foo/middleware/foo', async () => {
const html = await $fetch('/with-middleware')
expect(html).toContain('Injected by extended middleware')
})

expect(html).toContain('Sugar Counter 12 x 2 = 24')
it('extends bar/middleware/override.vue over foo/middleware/override.vue', async () => {
const html = await $fetch('/with-middleware-override')
expect(html).toContain('Injected by extended middleware from bar')
})
})
})
Loading

0 comments on commit 9a5f14b

Please sign in to comment.