]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat: allow beforeEnter as array
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 6 May 2019 19:47:46 +0000 (21:47 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 6 May 2019 19:47:46 +0000 (21:47 +0200)
__tests__/guards/route-beforeEnter.spec.js
src/router.ts
src/types/index.ts

index f1583eb24d5fc653090ba287847f2c609a32a0c3..ed48bcce66ef564def21c9043552f213ff44a839 100644 (file)
@@ -4,10 +4,13 @@ const expect = require('expect')
 const { HTML5History } = require('../../src/history/html5')
 const { Router } = require('../../src/router')
 const fakePromise = require('faked-promise')
-const { NAVIGATION_TYPES, createDom, noGuard } = require('../utils')
+const { NAVIGATION_TYPES, createDom, noGuard, tick } = require('../utils')
+
+/** @typedef {import('../../src/types').RouteRecord} RouteRecord */
+/** @typedef {import('../../src/router').RouterOptions} RouterOptions */
 
 /**
- * @param {Partial<import('../../src/router').RouterOptions> & { routes: import('../../src/types').RouteRecord[]}} options
+ * @param {Partial<RouterOptions> & { routes: RouteRecord[]}} options
  */
 function createRouter(options) {
   return new Router({
@@ -20,7 +23,8 @@ const Home = { template: `<div>Home</div>` }
 const Foo = { template: `<div>Foo</div>` }
 
 const beforeEnter = jest.fn()
-/** @type {import('../../src/types').RouteRecord[]} */
+const beforeEnters = [jest.fn(), jest.fn()]
+/** @type {RouteRecord[]} */
 const routes = [
   { path: '/', component: Home },
   { path: '/home', component: Home, beforeEnter },
@@ -30,10 +34,23 @@ const routes = [
     component: Foo,
     beforeEnter,
   },
+  {
+    path: '/multiple',
+    beforeEnter: beforeEnters,
+    component: Foo,
+  },
 ]
 
-beforeEach(() => {
+function resetMocks() {
   beforeEnter.mockReset()
+  beforeEnters.forEach(spy => {
+    spy.mockReset()
+    spy.mockImplementationOnce(noGuard)
+  })
+}
+
+beforeEach(() => {
+  resetMocks()
 })
 
 describe('beforeEnter', () => {
@@ -50,6 +67,18 @@ describe('beforeEnter', () => {
         expect(beforeEnter).toHaveBeenCalledTimes(1)
       })
 
+      it('supports an array of beforeEnter', async () => {
+        const router = createRouter({ routes })
+        await router[navigationMethod]('/multiple')
+        expect(beforeEnters[0]).toHaveBeenCalledTimes(1)
+        expect(beforeEnters[1]).toHaveBeenCalledTimes(1)
+        expect(beforeEnters[0]).toHaveBeenCalledWith(
+          expect.objectContaining({ path: '/multiple' }),
+          expect.objectContaining({ path: '/' }),
+          expect.any(Function)
+        )
+      })
+
       it('calls beforeEnter different records, same component', async () => {
         const router = createRouter({ routes })
         beforeEnter.mockImplementationOnce(noGuard)
@@ -81,6 +110,29 @@ describe('beforeEnter', () => {
         await p
         expect(router.currentRoute.fullPath).toBe('/foo')
       })
+
+      it('waits before navigating in an array of beforeEnter', async () => {
+        const [p1, r1] = fakePromise()
+        const [p2, r2] = fakePromise()
+        const router = createRouter({ routes })
+        beforeEnters[0].mockImplementationOnce(async (to, from, next) => {
+          await p1
+          next()
+        })
+        beforeEnters[1].mockImplementationOnce(async (to, from, next) => {
+          await p2
+          next()
+        })
+        const p = router[navigationMethod]('/multiple')
+        expect(router.currentRoute.fullPath).toBe('/')
+        expect(beforeEnters[1]).not.toHaveBeenCalled()
+        r1()
+        await p1
+        await tick()
+        r2()
+        await p
+        expect(router.currentRoute.fullPath).toBe('/multiple')
+      })
     })
   })
 })
index e41f6c1360dec45996f18726ae42a58013b3ad8c..3d0ddaf1fea2799bc9596afa3bb964dd635722cc 100644 (file)
@@ -179,8 +179,6 @@ export class Router {
     await this.runGuardQueue(guards)
 
     // check global guards beforeEach
-    // avoid if we are not changing route
-    // TODO: trigger on child navigation
     guards = []
     for (const guard of this.beforeGuards) {
       guards.push(guardToPromiseFn(guard, to, from))
@@ -201,12 +199,17 @@ export class Router {
     await this.runGuardQueue(guards)
 
     // check the route beforeEnter
-    // TODO: check children. Should we also check reused routes guards
     guards = []
     for (const record of to.matched) {
       // do not trigger beforeEnter on reused views
-      if (record.beforeEnter && from.matched.indexOf(record) < 0)
-        guards.push(guardToPromiseFn(record.beforeEnter, to, from))
+      if (record.beforeEnter && from.matched.indexOf(record) < 0) {
+        if (Array.isArray(record.beforeEnter)) {
+          for (const beforeEnter of record.beforeEnter)
+            guards.push(guardToPromiseFn(beforeEnter, to, from))
+        } else {
+          guards.push(guardToPromiseFn(record.beforeEnter, to, from))
+        }
+      }
     }
 
     // run the queue of per route beforeEnter guards
index cbee6c39a11530ff04f6e356bfbd43a4924e2a7e..1a56901946eeaec3caf515551f902ea5e5546139 100644 (file)
@@ -97,7 +97,7 @@ export type RouteComponent = {
 interface RouteRecordCommon {
   path: string // | RegExp
   name?: string
-  beforeEnter?: NavigationGuard
+  beforeEnter?: NavigationGuard | NavigationGuard[]
 }
 
 export type RouteRecordRedirectOption =
@@ -121,12 +121,6 @@ export type RouteRecord =
   | RouteRecordMultipleViews
   | RouteRecordRedirect
 
-export const START_RECORD: RouteRecord = {
-  path: '/',
-  // @ts-ignore
-  component: { render: h => h() },
-}
-
 // TODO: this should probably be generate by ensureLocation
 export const START_LOCATION_NORMALIZED: RouteLocationNormalized = {
   path: '/',