diff --git a/packages/nuxt/src/pages/runtime/validate.ts b/packages/nuxt/src/pages/runtime/validate.ts index 525042d78a..263eab3cdc 100644 --- a/packages/nuxt/src/pages/runtime/validate.ts +++ b/packages/nuxt/src/pages/runtime/validate.ts @@ -12,13 +12,10 @@ export default defineNuxtRouteMiddleware(async (to) => { if (result === true) { return } - if (import.meta.server) { - return result - } const error = createError({ - statusCode: 404, - statusMessage: `Page Not Found: ${to.fullPath}`, + statusCode: (result && result.statusCode) || 404, + statusMessage: (result && result.statusMessage) || `Page Not Found: ${to.fullPath}`, data: { path: to.fullPath, }, @@ -32,7 +29,7 @@ export default defineNuxtRouteMiddleware(async (to) => { // We pretend to have navigated to the invalid route so // that the user can return to the previous page with // the back button. - window.history.pushState({}, '', to.fullPath) + window?.history.pushState({}, '', to.fullPath) }) // We stop the navigation immediately before it resolves // if there is no other route matching it. diff --git a/test/basic.test.ts b/test/basic.test.ts index dff7cc4d99..a5318dfb0a 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -209,6 +209,45 @@ describe('pages', () => { await page.close() }) + it('validates routes with custom statusCode and statusMessage', async () => { + const CUSTOM_ERROR_CODE = 401 + const CUSTOM_ERROR_MESSAGE = 'Custom error message' + const ERROR_PAGE_TEXT = 'This is the error page' + const PAGE_TEXT = 'You should not see this' + + // Check status code and message on fetch + const res = await fetch('/validate-custom-error') + const serverText = await res.text() + + expect(res.status).toEqual(CUSTOM_ERROR_CODE) + expect(serverText).toContain(CUSTOM_ERROR_MESSAGE) + expect(serverText).not.toContain(PAGE_TEXT) + + // Client-side navigation + const { page } = await renderPage('/navigate-to-validate-custom-error') + await page.getByText('should throw a 401 error with custom message').click() + // error.vue has an h1 tag + await page.waitForSelector('h1') + + const clientText = await page.innerText('body') + + expect(clientText).toContain(CUSTOM_ERROR_MESSAGE) + expect(clientText).toContain(ERROR_PAGE_TEXT) + expect(clientText).not.toContain(PAGE_TEXT) + + await page.close() + + // Server-side navigation + const { page: serverPage } = await renderPage('/validate-custom-error') + const serverPageText = await serverPage.innerText('body') + + expect(serverPageText).toContain(CUSTOM_ERROR_MESSAGE) + expect(serverPageText).toContain(ERROR_PAGE_TEXT) + expect(serverPageText).not.toContain(PAGE_TEXT) + + await serverPage.close() + }) + it('returns 500 when there is an infinite redirect', async () => { const { status } = await fetch('/redirect-infinite', { redirect: 'manual' }) expect(status).toEqual(500) diff --git a/test/fixtures/basic/pages/navigate-to-validate-custom-error.vue b/test/fixtures/basic/pages/navigate-to-validate-custom-error.vue new file mode 100644 index 0000000000..bfd392448d --- /dev/null +++ b/test/fixtures/basic/pages/navigate-to-validate-custom-error.vue @@ -0,0 +1,14 @@ + + + diff --git a/test/fixtures/basic/pages/validate-custom-error.vue b/test/fixtures/basic/pages/validate-custom-error.vue new file mode 100644 index 0000000000..74c2a09a1d --- /dev/null +++ b/test/fixtures/basic/pages/validate-custom-error.vue @@ -0,0 +1,12 @@ + + +