From: Eduardo San Martin Morote Date: Tue, 17 Sep 2019 17:09:26 +0000 (+0200) Subject: test(ssr): add basic test X-Git-Tag: v4.0.0-alpha.0~228^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6ff985a17a4bf8dc44569a8e2750dfa8fe83e492;p=thirdparty%2Fvuejs%2Frouter.git test(ssr): add basic test --- diff --git a/__tests__/ssr/basic.spec.js b/__tests__/ssr/basic.spec.js index d768414d..a553485c 100644 --- a/__tests__/ssr/basic.spec.js +++ b/__tests__/ssr/basic.spec.js @@ -1,69 +1,31 @@ -/** @type {import('vue').VueConstructor} */ -// @ts-ignore -const Vue = require('vue') -const Router = require('../../src').default -const { components, isMocha } = require('../utils') -const { createRenderer } = require('vue-server-renderer') +const { renderApp, renderer } = require('./shared') -describe.skip('SSR: basicRenderer', () => { - Vue.use(Router) - - function createRouter() { - // TODO: a more complex routing that can be used for most tests - return new Router({ - mode: 'history', - routes: [ - { - path: '/', - component: components.Home, - }, - { - path: '/foo', - component: components.Foo, - }, - ], - }) - } - - function createApp() { - // create router instance - const router = createRouter() - - const app = new Vue({ - // @ts-ignore - router, - render: h => h('div', {}, [h('RouterView')]), - }) - - // return both the app and the router - return { app, router } - } - - function renderApp(context) { - return new Promise((resolve, reject) => { - const { app, router } = createApp() - - // set server-side router's location - router.push(context.url) - - // wait until router has resolved possible async components and hooks - // TODO: rename the promise one to isReady - router.onReady().then(() => { - // const matchedComponents = router.getMatchedComponents() - // no matched routes, reject with 404 - if (!matchedComponents.length) { - return reject({ code: 404 }) - } +describe('SSR: basicRenderer', () => { + it('renders the view', async () => { + const app = await renderApp({ url: '/' }) + const result = await renderer.renderToString(app) + expect(result).toMatchInlineSnapshot( + `"
Home
"` + ) + }) - // the Promise should resolve to the app instance so it can be rendered - resolve(app) - }, reject) - }) - } + /** + * TODO: + * - KeepAlive + * - Suspense + * - Navigation Guards + * - Cancelled + * - Redirection + * - Async components + * - Views + * - Inner components + */ - it('should work', done => { - renderToString( - new Vue({ + it('should work', async () => { + const app = await renderApp( + { url: '/' }, + {}, + { template: `

yoyo

@@ -98,42 +60,20 @@ describe.skip('SSR: basicRenderer', () => { }) }, }, - }), - (err, result) => { - expect(err).toBeNull() - expect(result).toContain( - '
' + - '

yoyo

' + - '
' + - 'hi ' + - ' ' + - ' ' + - '
test
' + - 'testAsync' + - '
' - ) - done() } ) - }) + const result = await renderer.renderToString(app) - // #5941 - it('should work peoperly when accessing $ssrContext in root component', done => { - let ssrContext - renderToString( - new Vue({ - template: ` -
- `, - created() { - ssrContext = this.$ssrContext - }, - }), - err => { - expect(err).toBeNull() - expect(ssrContext).toBeUndefined() - done() - } + expect(result).toContain( + '
' + + '

yoyo

' + + '
' + + 'hi ' + + ' ' + + ' ' + + '
test
' + + 'testAsync' + + '
' ) }) }) diff --git a/__tests__/ssr/shared.ts b/__tests__/ssr/shared.ts new file mode 100644 index 00000000..143fac83 --- /dev/null +++ b/__tests__/ssr/shared.ts @@ -0,0 +1,76 @@ +import Vue from 'vue' +import Router from '../../src' +import { components } from '../utils' + +import { createRenderer } from 'vue-server-renderer' +import { RouterOptions } from '../../src/router' + +Vue.use(Router) + +export const renderer = createRenderer() + +export function createRouter(options?: Partial) { + // TODO: a more complex routing that can be used for most tests + return new Router({ + mode: 'history', + routes: [ + { + path: '/', + component: components.Home, + }, + { + path: '/foo', + component: components.Foo, + }, + ], + ...options, + }) +} + +export function createApp( + routerOptions?: Partial, + options?: any +) { + // create router instance + const router = createRouter(routerOptions) + + const app = new Vue({ + // @ts-ignore + router, + template: `
+ +
`, + ...options, + // render: h => h('div', {}, [h('RouterView')]), + }) + + // return both the app and the router + return { app, router } +} + +export function renderApp( + context: { url: string }, + routerOptions?: Partial, + vueOptions?: any +) { + return new Promise['app']>((resolve, reject) => { + const { app, router } = createApp(routerOptions, vueOptions) + + // set server-side router's location + router.push(context.url).catch(err => {}) + + // wait until router has resolved possible async components and hooks + // TODO: rename the promise one to isReady + router.onReady().then(() => { + // const matchedComponents = router.getMatchedComponents() + const matchedComponents = router.currentRoute.matched + // no matched routes, reject with 404 + if (!matchedComponents.length) { + return reject({ code: 404 }) + } + + // the Promise should resolve to the app instance so it can be rendered + resolve(app) + }, reject) + }) +} diff --git a/src/index.ts b/src/index.ts index 7c596c08..66033ec7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,7 @@ const plugin: PluginFunction = Vue => { // true ) - router.doInitialNavigation() + router.doInitialNavigation().catch(() => {}) } else { // @ts-ignore we are adding this this._routerRoot = (this.$parent && this.$parent._routerRoot) || this diff --git a/src/router.ts b/src/router.ts index 5fa91392..66f36d13 100644 --- a/src/router.ts +++ b/src/router.ts @@ -497,9 +497,13 @@ export class Router { */ protected markAsReady(err?: any): void { if (this.ready) return - for (const [resolve, reject] of this.onReadyCbs) { - if (err) reject(err) - else resolve() + for (const [resolve] of this.onReadyCbs) { + // TODO: is this okay? + // always resolve, as the router is ready even if there was an error + // @ts-ignore + resolve(err) + // if (err) reject(err) + // else resolve() } this.onReadyCbs = [] this.ready = true @@ -517,6 +521,7 @@ export class Router { try { await this.navigate(toLocation, this.currentRoute) } catch (error) { + this.markAsReady(error) if (NavigationGuardRedirect.is(error)) { // push was called while waiting in guards if (this.pendingLocation !== toLocation) { @@ -533,13 +538,16 @@ export class Router { throw new NavigationCancelled(toLocation, this.currentRoute) } + // this throws, so nothing ahead happens this.triggerError(error) } } // push was called while waiting in guards if (this.pendingLocation !== toLocation) { - throw new NavigationCancelled(toLocation, this.currentRoute) + const error = new NavigationCancelled(toLocation, this.currentRoute) + this.markAsReady(error) + throw error } // NOTE: here we removed the pushing to history part as the history @@ -552,6 +560,7 @@ export class Router { // navigation is confirmed, call afterGuards for (const guard of this.afterGuards) guard(toLocation, from) + this.markAsReady() return this.currentRoute }