Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nuxt): ensure useError is called with nuxt app context #20585

Merged
merged 12 commits into from May 1, 2023
Merged
5 changes: 2 additions & 3 deletions packages/nuxt/src/app/composables/cookie.ts
Expand Up @@ -48,11 +48,10 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
}
}
const unhook = nuxtApp.hooks.hookOnce('app:rendered', writeFinalCookieValue)
const writeAndUnhook = () => {
nuxtApp.hooks.hookOnce('app:error', () => {
unhook() // don't write cookie subsequently when app:rendered is called
return writeFinalCookieValue()
}
nuxtApp.hooks.hookOnce('app:error', writeAndUnhook)
})
}

return cookie as CookieRef<T>
Expand Down
4 changes: 3 additions & 1 deletion packages/nuxt/src/app/composables/error.ts
Expand Up @@ -13,8 +13,10 @@ export const showError = (_err: string | Error | Partial<NuxtError>) => {

try {
const nuxtApp = useNuxtApp()
nuxtApp.callHook('app:error', err)
const error = useError()
if (process.client) {
nuxtApp.hooks.callHook('app:error', err)
}
error.value = error.value || err
} catch {
throw err
Expand Down
6 changes: 4 additions & 2 deletions packages/nuxt/src/core/runtime/nitro/error.ts
@@ -1,7 +1,7 @@
import { joinURL, withQuery } from 'ufo'
import type { NitroErrorHandler } from 'nitropack'
import type { H3Error } from 'h3'
import { getRequestHeaders, setResponseHeader, setResponseStatus } from 'h3'
import { appendResponseHeader, getRequestHeaders, setResponseHeader, setResponseStatus } from 'h3'
import { useNitroApp, useRuntimeConfig } from '#internal/nitro'
import { isJsonRequest, normalizeError } from '#internal/nitro/utils'

Expand Down Expand Up @@ -69,7 +69,9 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
}

for (const [header, value] of res.headers.entries()) {
setResponseHeader(event, header, value)
// TODO: remove `appendResponseHeader` when we drop support for node 16
const handler = header.toLowerCase() === 'set-cookie' ? appendResponseHeader : setResponseHeader
handler(event, header, value)
}

setResponseStatus(event, res.status && res.status !== 200 ? res.status : undefined, res.statusText)
Expand Down
12 changes: 8 additions & 4 deletions test/basic.test.ts
Expand Up @@ -114,8 +114,9 @@ describe('pages', () => {
})

it('validates routes', async () => {
const { status } = await fetch('/forbidden')
const { status, headers } = await fetch('/forbidden')
expect(status).toEqual(404)
expect(headers.get('Set-Cookie')).toContain('set-in-plugin=true; Path=/')

const page = await createPage('/navigate-to-forbidden')
await page.waitForLoadState('networkidle')
Expand All @@ -135,8 +136,11 @@ describe('pages', () => {
expect(status).toEqual(500)
})

it('render 404', async () => {
const html = await $fetch('/not-found')
it('render catchall page', async () => {
const res = await fetch('/not-found')
expect(res.status).toEqual(200)

const html = await res.text()

// Snapshot
// expect(html).toMatchInlineSnapshot()
Expand Down Expand Up @@ -578,7 +582,7 @@ describe('errors', () => {

it('should render a HTML error page', async () => {
const res = await fetch('/error')
expect(res.headers.get('Set-Cookie')).toBe('some-error=was%20set; Path=/')
expect(res.headers.get('Set-Cookie')).toContain('set-in-plugin=true; Path=/, some-error=was%20set; Path=/')
expect(await res.text()).toContain('This is a custom error')
})

Expand Down
2 changes: 1 addition & 1 deletion test/bundle.test.ts
Expand Up @@ -45,7 +45,7 @@ describe.skipIf(isWindows || process.env.TEST_BUILDER === 'webpack' || process.e

it('default server bundle size', async () => {
stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"66.6k"')
expect(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"66.7k"')

const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"2654k"')
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/basic/plugins/cookie.ts
@@ -0,0 +1,3 @@
export default defineNuxtPlugin(() => {
useCookie('set-in-plugin').value = 'true'
})