await router.push('/guard')
expect(beforeRouteLeave).not.toHaveBeenCalled()
+ // simulate a mounted route component
+ router.currentRoute.value.matched[0].instances.default = {} as any
+
await router.push('/foo')
expect(beforeRouteLeave).toHaveBeenCalledTimes(1)
})
+ it('does not call beforeRouteLeave guard if the view is not mounted', async () => {
+ const router = createRouter({ routes })
+ beforeRouteLeave.mockImplementationOnce((to, from, next) => {
+ next()
+ })
+ await router.push('/guard')
+ expect(beforeRouteLeave).not.toHaveBeenCalled()
+
+ // usually we would have to simulate a mounted route component
+ // router.currentRoute.value.matched[0].instances.default = {} as any
+
+ await router.push('/foo')
+ expect(beforeRouteLeave).not.toHaveBeenCalled()
+ })
+
it('calls beforeRouteLeave guard on navigation between children', async () => {
const router = createRouter({ routes })
await router.push({ name: 'nested-path' })
+
+ // simulate a mounted route component
+ router.currentRoute.value.matched[0].instances.default = {} as any
+ router.currentRoute.value.matched[1].instances.default = {} as any
+
resetMocks()
await router.push({ name: 'nested-path-b' })
expect(nested.nestedEmpty).not.toHaveBeenCalled()
next()
})
+ // simulate a mounted route component
+ router.currentRoute.value.matched[0].instances.default = {} as any
+ router.currentRoute.value.matched[1].instances.default = {} as any
+ router.currentRoute.value.matched[2].instances.default = {} as any
+
await router.push('/')
expect(nested.parent).toHaveBeenCalledTimes(1)
expect(nested.nestedNested).toHaveBeenCalledTimes(1)
await router.push('/guard/valid')
// not called on initial navigation
expect(beforeRouteUpdate).not.toHaveBeenCalled()
+ // simulate a mounted route component
+ router.currentRoute.value.matched[0].instances.default = {} as any
await router.push('/guard/other')
expect(beforeRouteUpdate).toHaveBeenCalledTimes(1)
})
+ it('does not call beforeRouteUpdate guard if the view is not mounted', async () => {
+ const router = createRouter({ routes })
+ beforeRouteUpdate.mockImplementationOnce(noGuard)
+ await router.push('/guard/valid')
+ // not called on initial navigation
+ expect(beforeRouteUpdate).not.toHaveBeenCalled()
+ // usually we would have to simulate a mounted route component
+ // router.currentRoute.value.matched[0].instances.default = {} as any
+ await router.push('/guard/other')
+ expect(beforeRouteUpdate).not.toHaveBeenCalled()
+ })
+
it('waits before navigating', async () => {
const [promise, resolve] = fakePromise()
const router = createRouter({ routes })
expect(component).toHaveBeenCalledTimes(1)
expect(spy).toHaveBeenCalledTimes(0)
+ // simulate a mounted route component
+ router.currentRoute.value.matched[0].instances.default = {} as any
+
await router.push('/')
expect(spy).toHaveBeenCalledTimes(1)
})
expect(component).toHaveBeenCalledTimes(1)
expect(spy).toHaveBeenCalledTimes(0)
+ // simulate a mounted route component
+ router.currentRoute.value.matched[0].instances.default = {} as any
+
await router.push('/bar')
expect(spy).toHaveBeenCalledTimes(1)
})
const NamedViews: RouteComponent[] = looper.map(i => ({
name: 'part-' + i,
- template: `<div class="named part-${i}">Part ${i}. Updated <span class="count">{{ count }}</span></div>`,
+ template: `<div class="named" id="part-${i}">Part ${i}. Updated <span class="count">{{ count }}</span></div>`,
data: () => ({ count: 0 }),
beforeRouteUpdate(to, from, next) {
+ console.log('update of', i)
// @ts-ignore
- // this.count++
+ this.count++
next()
},
}))
mountBtn.addEventListener('click', () => {
let app = (apps[i] = createApp({
template: `
- <div id="app-${i}">
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/users/1">User 1</router-link></li>
<router-view></router-view>
<router-view name="part-${n}"></router-view>
- </div>
`,
}))
app.use(router)
.assert.containsText('#app-1 .home', 'Home')
// toggle multiple times
.click('#app-1 li:nth-child(2) a')
- .assert.containsText('#app-1 .count', '0')
+ .assert.containsText('#part-1 .count', '0')
.click('#app-1 li:nth-child(3) a')
- .assert.containsText('#app-1 .count', '1')
+ .assert.containsText('#part-1 .count', '1')
.click('#mount2')
- .assert.containsText('#app-2 .user', 'User 2')
+ .assert.containsText('#app-2 .user', 'User')
.click('#app-1 li:nth-child(2) a')
// first one keeps updating
- .assert.containsText('#app-1 .count', '2')
+ .assert.containsText('#part-1 .count', '2')
// second app only updated once
- .assert.containsText('#app-2 .count', '1')
+ .assert.containsText('#part-2 .count', '1')
.click('#mount3')
},
}
rawComponent = () => promise
}
+ // skip update and leave guards if the route component is not mounted
+ if (guardType !== 'beforeRouteEnter' && !record.instances[name]) continue
+
if (isRouteComponent(rawComponent)) {
// __vccOpts is added by vue-class-component and contain the regular options
let options: ComponentOptions =