diff --git a/lib/app/client.js b/lib/app/client.js index d210a0c24b..c2c5b0c4bd 100644 --- a/lib/app/client.js +++ b/lib/app/client.js @@ -292,11 +292,28 @@ async function render (to, from, next) { // Call .validate() let isValid = true - Components.forEach((Component) => { - if (!isValid) return - if (typeof Component.options.validate !== 'function') return - isValid = Component.options.validate(app.context) - }) + let validationError + try { + for (const Component of Components) { + if (typeof Component.options.validate !== 'function') { + continue + } + + isValid = await Component.options.validate(app.context) + + if (!isValid) { + break + } + } + } catch (validationError) { + // ...If .validate() threw an error + this.error({ + statusCode: validationError.statusCode || '500', + message: validationError.message + }) + return next() + } + // ...If .validate() returned false if (!isValid) { this.error({ statusCode: 404, message: `<%= messages.error_404 %>` }) diff --git a/lib/app/server.js b/lib/app/server.js index 76070d8504..4e0f1c5e78 100644 --- a/lib/app/server.js +++ b/lib/app/server.js @@ -154,11 +154,28 @@ export default async (ssrContext) => { ** Call .validate() */ let isValid = true - Components.forEach((Component) => { - if (!isValid) return - if (typeof Component.options.validate !== 'function') return - isValid = Component.options.validate(app.context) - }) + let validationError + try { + for (const Component of Components) { + if (typeof Component.options.validate !== 'function') { + continue + } + + isValid = await Component.options.validate(app.context) + + if (!isValid) { + break + } + } + } catch (validationError) { + // ...If .validate() threw an error + app.context.error({ + statusCode: validationError.statusCode || '500', + message: validationError.message + }) + return renderErrorPage() + } + // ...If .validate() returned false if (!isValid) { // Don't server-render the page in generate mode diff --git a/test/e2e/basic.browser.test.js b/test/e2e/basic.browser.test.js index 70c73eed73..86442cceee 100644 --- a/test/e2e/basic.browser.test.js +++ b/test/e2e/basic.browser.test.js @@ -123,12 +123,27 @@ describe('basic browser', () => { expect(error.message).toBe('This page could not be found') }) + test('/validate-async should display a 404', async () => { + await page.nuxt.navigate('/validate-async') + + const error = await page.nuxt.errorData() + + expect(error.statusCode).toBe(404) + expect(error.message).toBe('This page could not be found') + }) + test('/validate?valid=true', async () => { await page.nuxt.navigate('/validate?valid=true') expect(await page.$text('h1')).toBe('I am valid') }) + test('/validate-async?valid=true', async () => { + await page.nuxt.navigate('/validate-async?valid=true') + + expect(await page.$text('h1')).toBe('I am valid') + }) + test('/redirect', async () => { await page.nuxt.navigate('/redirect') diff --git a/test/fixtures/basic/pages/validate-async.vue b/test/fixtures/basic/pages/validate-async.vue new file mode 100644 index 0000000000..8637d0f81a --- /dev/null +++ b/test/fixtures/basic/pages/validate-async.vue @@ -0,0 +1,15 @@ + + + diff --git a/test/unit/basic.ssr.test.js b/test/unit/basic.ssr.test.js index e56a33de73..f9e6f6a6f5 100644 --- a/test/unit/basic.ssr.test.js +++ b/test/unit/basic.ssr.test.js @@ -96,11 +96,21 @@ describe('basic ssr', () => { expect(html.includes('This page could not be found')).toBe(true) }) + test('/validate-async should display a 404', async () => { + const { html } = await nuxt.renderRoute('/validate-async') + expect(html.includes('This page could not be found')).toBe(true) + }) + test('/validate?valid=true', async () => { const { html } = await nuxt.renderRoute('/validate?valid=true') expect(html.includes('

I am valid

')).toBe(true) }) + test('/validate-async?valid=true', async () => { + const { html } = await nuxt.renderRoute('/validate-async?valid=true') + expect(html.includes('

I am valid

')).toBe(true) + }) + test('/before-enter', async () => { const { html } = await nuxt.renderRoute('/before-enter') expect(html.includes('

Index page

')).toBe(true)