Skip to content

Commit

Permalink
test: edge cases isReady
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Feb 28, 2022
1 parent 509fc0d commit 48bcbe5
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 8 deletions.
111 changes: 111 additions & 0 deletions __tests__/isReady.spec.ts
@@ -0,0 +1,111 @@
import { createMemoryHistory, createRouter } from '../src'
import { components } from './utils'
import { RouteRecordRaw } from '../src/types'

// generic component because we are not displaying anything so it doesn't matter
const component = components.Home

const routes: RouteRecordRaw[] = [
{ path: '/', component },
{ path: '/bar', component },
{ path: '/foo', component, name: 'Foo' },
{
path: '/fail-lazy',
component: async () => {
throw new Error('async')
},
},
]

describe('isReady', () => {
function newRouter(
options: Partial<Parameters<typeof createRouter>[0]> = {}
) {
const history = options.history || createMemoryHistory()
const router = createRouter({ history, routes, ...options })

return router
}

it('resolves a normal navigation', async () => {
const router = newRouter()
router.push('/foo')
await expect(router.isReady()).resolves.toBe(undefined)
// can be called again
await expect(router.isReady()).resolves.toBe(undefined)
})

it('resolves a redirected navigation', async () => {
const router = newRouter()
router.beforeEach(to => (to.path === '/bar' ? true : '/bar'))
router.push('/foo')
await expect(router.isReady()).resolves.toBe(undefined)
expect(router.currentRoute.value).toMatchObject({
redirectedFrom: expect.objectContaining({ path: '/foo' }),
})
// can be called again
await expect(router.isReady()).resolves.toBe(undefined)
})

it('rejects when an error is thrown in a navigation guard', async () => {
const router = newRouter()
const errorSpy = jest.fn()
const error = new Error('failed')
router.onError(errorSpy)
const remove = router.beforeEach(async () => {
throw error
})
router.push('/foo').catch(() => {})
await expect(router.isReady()).rejects.toBe(error)
expect(errorSpy).toHaveBeenCalledTimes(1)
expect(errorSpy).toHaveBeenCalledWith(
error,
// to
expect.objectContaining({ path: '/foo' }),
// from
expect.objectContaining({ path: '/' })
)

// result can change
remove()
router.push('/foo').catch(() => {})
await expect(router.isReady()).resolves.toBe(undefined)
expect(errorSpy).toHaveBeenCalledTimes(1)
})

it('rejects a cancelled navigation', async () => {
const router = newRouter()
const errorSpy = jest.fn()
router.onError(errorSpy)
const remove = router.beforeEach(() => false)
router.push('/foo').catch(() => {})
await expect(router.isReady()).rejects.toMatchObject({
to: expect.objectContaining({ path: '/foo' }),
from: expect.objectContaining({ path: '/' }),
})
expect(errorSpy).toHaveBeenCalledTimes(0)

// can be checked again
router.push('/foo').catch(() => {})
await expect(router.isReady()).rejects.toMatchObject({
to: expect.objectContaining({ path: '/foo' }),
from: expect.objectContaining({ path: '/' }),
})
expect(errorSpy).toHaveBeenCalledTimes(0)

// result can change
remove()
router.push('/foo').catch(() => {})
await expect(router.isReady()).resolves.toBe(undefined)
expect(errorSpy).toHaveBeenCalledTimes(0)
})

it('rejects failed lazy loading', async () => {
const router = newRouter()
const errorSpy = jest.fn()
router.onError(errorSpy)
router.push('/fail-lazy').catch(() => {})
await expect(router.isReady()).rejects.toEqual(expect.any(Error))
expect(errorSpy).toHaveBeenCalledTimes(1)
})
})
21 changes: 13 additions & 8 deletions src/router.ts
Expand Up @@ -1103,14 +1103,19 @@ export function createRouter(options: RouterOptions): Router {
* only be called once, otherwise does nothing.
* @param err - optional error
*/
function markAsReady(err?: any): void {
if (ready) return
ready = true
setupListeners()
readyHandlers
.list()
.forEach(([resolve, reject]) => (err ? reject(err) : resolve()))
readyHandlers.reset()
function markAsReady<E = any>(err: E): E
function markAsReady<E = any>(): void
function markAsReady<E = any>(err?: E): E | void {
if (!ready) {
// still not ready if an error happened
ready = !err
setupListeners()
readyHandlers
.list()
.forEach(([resolve, reject]) => (err ? reject(err) : resolve()))
readyHandlers.reset()
}
return err
}

// Scroll behavior
Expand Down

0 comments on commit 48bcbe5

Please sign in to comment.