Skip to content

Commit

Permalink
feat: skip navigation guards
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Dec 22, 2020
1 parent ad037b5 commit 6f6f458
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 69 deletions.
5 changes: 0 additions & 5 deletions __tests__/components.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { mount } from '@vue/test-utils'
import { injectRouterMock } from '../src'

describe('components', () => {
beforeAll(() => {
injectRouterMock()
})

it('stubs router link', async () => {
const wrapper = mount(
{
Expand Down
2 changes: 1 addition & 1 deletion __tests__/fixtures/Test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineComponent, getCurrentInstance, h, PropType } from 'vue'
import { defineComponent, h, PropType } from 'vue'
import {
NavigationGuard,
onBeforeRouteLeave,
Expand Down
15 changes: 9 additions & 6 deletions __tests__/injections.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { mount } from '@vue/test-utils'
import { useRoute, useRouter } from 'vue-router'
import { injectRouterMock, createRouterMock } from '../src'
import { getRouter } from '../src'

describe('Injections', () => {
const router = createRouterMock()
beforeAll(() => {
injectRouterMock(router)
})

it('injects the router instance', async () => {
const router = getRouter()
const wrapper = mount({
render: () => null,
setup() {
Expand All @@ -20,6 +16,12 @@ describe('Injections', () => {
expect(wrapper.vm.$router).toBe(router)
})

it('sets the wrapper router property', () => {
const wrapper = mount({ render: () => null })
const router = getRouter()
expect(wrapper.router).toBe(router)
})

it('injects the current route', async () => {
const wrapper = mount({
render: () => null,
Expand All @@ -28,6 +30,7 @@ describe('Injections', () => {
return { r }
},
})
const router = getRouter()

expect(wrapper.vm.$route).toBe(wrapper.vm.r)
expect(wrapper.vm.r).toMatchObject({ fullPath: '/' })
Expand Down
118 changes: 78 additions & 40 deletions __tests__/navigations.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { mount } from '@vue/test-utils'
import { NavigationFailureType } from 'vue-router'
import { injectRouterMock, createRouterMock, EmptyView } from '../src'
import {
injectRouterMock,
createRouterMock,
EmptyView,
getRouter,
} from '../src'
import Test from './fixtures/Test'

describe('Navigations', () => {
const router = createRouterMock()
beforeEach(() => {
injectRouterMock(router)
})

it('can check calls on push', async () => {
const wrapper = mount(Test)

Expand All @@ -32,13 +32,15 @@ describe('Navigations', () => {

it('rejects next navigation with an error', async () => {
const wrapper = mount(Test)
const router = getRouter()
const error = new Error('fail')
router.setNextGuardReturn(error)
await expect(wrapper.vm.$router.push('/foo')).rejects.toBe(error)
})

it('can abort the next navigation', async () => {
const wrapper = mount(Test)
const router = getRouter()
router.setNextGuardReturn(false)
await expect(wrapper.vm.$router.push('/foo')).resolves.toMatchObject({
type: NavigationFailureType.aborted,
Expand Down Expand Up @@ -71,72 +73,106 @@ describe('Navigations', () => {
})

describe('in-component guards', () => {
it('ignores guards by default with no guard', async () => {
const router = createRouterMock()
async function factory(
options: Parameters<typeof createRouterMock>[0] = {}
) {
const leaveGuard = jest.fn()
const updateGuard = jest.fn()
const beforeRouteEnter = jest.fn()
const beforeRouteUpdate = jest.fn()
const beforeRouteLeave = jest.fn()

const RouteComponent = {
...Test,
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave,
}
const router = createRouterMock(options)
injectRouterMock(router)
router.addRoute({ path: '/test', component: Test })
router.addRoute({ path: '/test', component: RouteComponent })
await router.push('/test')

const leaveGuard = jest.fn()
const updateGuard = jest.fn()
mount(RouteComponent, { props: { leaveGuard, updateGuard } })

mount(Test, { props: { leaveGuard, updateGuard } })
return {
router,
leaveGuard,
updateGuard,
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave,
}
}

it('ignores guards by default with no guard', async () => {
const {
router,
leaveGuard,
updateGuard,
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave,
} = await factory()

await router.push('/test#two')
expect(beforeRouteEnter).not.toHaveBeenCalled()
expect(updateGuard).not.toHaveBeenCalled()
expect(beforeRouteUpdate).not.toHaveBeenCalled()

await router.push('/foo')
expect(leaveGuard).not.toHaveBeenCalled()
expect(beforeRouteLeave).not.toHaveBeenCalled()
})

it('ignores guards by default with a guard', async () => {
const router = createRouterMock()
injectRouterMock(router)
router.addRoute({ path: '/test', component: Test })
await router.push('/test')

const leaveGuard = jest.fn()
const updateGuard = jest.fn()

mount(Test, { props: { leaveGuard, updateGuard } })
const {
router,
leaveGuard,
updateGuard,
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave,
} = await factory()

router.setNextGuardReturn(true)
await router.push('/test#two')
expect(beforeRouteEnter).not.toHaveBeenCalled()
expect(updateGuard).not.toHaveBeenCalled()
expect(beforeRouteUpdate).not.toHaveBeenCalled()

router.setNextGuardReturn(true)
await router.push('/foo')
expect(leaveGuard).not.toHaveBeenCalled()
expect(beforeRouteLeave).not.toHaveBeenCalled()
})

it('runs guards without a guard return set', async () => {
const router = createRouterMock({ runInComponentGuards: true })
injectRouterMock(router)
router.addRoute({ path: '/test', component: Test })
await router.push('/test')

const leaveGuard = jest.fn()
const updateGuard = jest.fn()

mount(Test, { props: { leaveGuard, updateGuard } })

const {
router,
leaveGuard,
updateGuard,
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave,
} = await factory({
runInComponentGuards: true,
})

expect(beforeRouteEnter).toHaveBeenCalled()
await router.push('/test#two')
expect(updateGuard).toHaveBeenCalled()
expect(beforeRouteUpdate).toHaveBeenCalled()

await router.push('/foo')
expect(leaveGuard).toHaveBeenCalled()
expect(beforeRouteLeave).toHaveBeenCalled()
})

it('runs guards with a guard', async () => {
const router = createRouterMock({ runInComponentGuards: true })
injectRouterMock(router)
router.addRoute({ path: '/test', component: Test })
await router.push('/test')

const leaveGuard = jest.fn()
const updateGuard = jest.fn()

mount(Test, { props: { leaveGuard, updateGuard } })
const { router, leaveGuard, updateGuard } = await factory({
runInComponentGuards: true,
})

router.setNextGuardReturn(true)
await router.push('/test#two')
Expand All @@ -150,13 +186,15 @@ describe('Navigations', () => {

it('can redirect the next navigation', async () => {
const wrapper = mount(Test)
const router = getRouter()
router.setNextGuardReturn('/bar')
await expect(wrapper.vm.$router.push('/foo')).resolves.toBe(undefined)
expect(wrapper.text()).toBe('/bar')
})

it.skip('can wait for an ongoing navigation', async () => {
const wrapper = mount(Test)
const router = getRouter()

// to force async navigation
router.setNextGuardReturn('/bar')
Expand Down
4 changes: 0 additions & 4 deletions __tests__/routeLocation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ import { createRouterMock, injectRouterMock } from '../src'
import Test from './fixtures/Test'

describe('Route location', () => {
beforeAll(() => {
injectRouterMock()
})

it('creates router properties', async () => {
const wrapper = mount(Test)

Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = {
collectCoverage: true,
collectCoverageFrom: ['<rootDir>/src/**/*.ts'],
testMatch: ['<rootDir>/__tests__/**/*.spec.ts'],
setupFiles: ['<rootDir>/jest.setup.js'],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
globals: {
__DEV__: true,
__BROWSER__: true,
Expand Down
10 changes: 8 additions & 2 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
const { routerMockPlugin } = require('./src')
const { VueRouterMock, createRouterMock, injectRouterMock } = require('./src')
const { config } = require('@vue/test-utils')

// config.plugins.VueWrapper.install(routerMockPlugin)
const router = createRouterMock()

beforeEach(() => {
injectRouterMock(router)
})

config.plugins.VueWrapper.install(VueRouterMock)
17 changes: 16 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
export { injectRouterMock, createProvide } from './injections'
export { RouterMock, createRouterMock, EmptyView } from './router'
export {
RouterMock,
createRouterMock,
EmptyView,
RouterMockOptions,
} from './router'
export { plugin as VueRouterMock, getRouter } from './plugin'

import { RouterMock } from './router'
import { ComponentPublicInstance } from 'vue'

declare module '@vue/test-utils' {
export class VueWrapper<T extends ComponentPublicInstance> {
router: RouterMock
}
}

// TODO: find how to do
// import { RouterMock } from './router'
Expand Down
40 changes: 40 additions & 0 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { config, VueWrapper } from '@vue/test-utils'
import { routerKey } from 'vue-router'
import { RouterMock } from './router'

export function plugin(
wrapper: VueWrapper<any>
// options: Pick<
// RouterOptions,
// | 'end'
// | 'sensitive'
// | 'strict'
// | 'linkActiveClass'
// | 'linkExactActiveClass'
// | 'parseQuery'
// | 'stringifyQuery'
// > &
// RouterMockOptions = {}
) {
// if (!config.global.components.RouterView) {
// const router = createRouterMock(options)
// injectRouterMock(router)
// }

const router: RouterMock = getRouter()

// set all instances when installing the plugin
router.currentRoute.value.matched.forEach((record) => {
for (const name in record.components) {
record.instances[name] = wrapper.vm
}
})

wrapper.router = router

return wrapper
}

export function getRouter() {
return config.global.provide[routerKey as any] as RouterMock
}

0 comments on commit 6f6f458

Please sign in to comment.