]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
test: refactor onBeforeRouteUpdate
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 1 Mar 2021 09:33:44 +0000 (10:33 +0100)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 1 Mar 2021 09:33:44 +0000 (10:33 +0100)
__tests__/guards/onBeforeRouteUpdate.spec.ts
__tests__/utils.ts

index dab3d99a0db95a2b6b6128ad8106cc1cecb73621..af11c91a21cde10b055be64d2a498733e53236bf 100644 (file)
@@ -5,46 +5,127 @@ import {
   createRouter,
   createMemoryHistory,
   onBeforeRouteUpdate,
+  RouterView,
+  RouteRecordRaw,
 } from '../../src'
-import { createApp, defineComponent } from 'vue'
+import { defineComponent, h, ComponentOptions, FunctionalComponent } from 'vue'
+import { mount } from '@vue/test-utils'
+import { delay } from '../utils'
 
 const component = {
   template: '<div>Generic</div>',
 }
 
+function withSpy(name?: string, isAsync = false) {
+  const spy = jest.fn()
+  const Component = defineComponent({
+    name,
+    template: `<p>${name || 'No Name'}</p>`,
+    setup() {
+      onBeforeRouteUpdate(spy)
+      return isAsync ? delay(100).then(() => ({})) : {}
+    },
+  })
+
+  return { spy, Component }
+}
+
+type ComponentToMount =
+  | Parameters<typeof mount>[0]
+  | ComponentOptions
+  | FunctionalComponent
+
+function factory(
+  routes: RouteRecordRaw[],
+  componentToMount: ComponentToMount = () => h(RouterView)
+) {
+  const router = createRouter({
+    history: createMemoryHistory(),
+    routes,
+  })
+  const wrapper = mount(componentToMount as any, {
+    global: {
+      plugins: [router],
+    },
+  })
+
+  return { wrapper, router }
+}
 describe('onBeforeRouteUpdate', () => {
   it('removes update guards when leaving', async () => {
-    const spy = jest.fn()
-    const WithLeave = defineComponent({
-      template: `text`,
-      setup() {
-        onBeforeRouteUpdate(spy)
-      },
-    })
-
-    const router = createRouter({
-      history: createMemoryHistory(),
-      routes: [
-        { path: '/', component },
-        { path: '/foo', component: WithLeave as any },
-      ],
-    })
-    const app = createApp({
-      template: `
-      <router-view />
-      `,
-    })
-    app.use(router)
-    const rootEl = document.createElement('div')
-    document.body.appendChild(rootEl)
-    app.mount(rootEl)
+    const { spy: routeUpdate, Component } = withSpy()
+
+    const { router } = factory([
+      { path: '/', component },
+      { path: '/foo', component: Component },
+    ])
 
     await router.isReady()
     await router.push('/foo')
+    expect(routeUpdate).toHaveBeenCalledTimes(0)
     await router.push('/foo?q')
+    expect(routeUpdate).toHaveBeenCalledTimes(1)
     await router.push('/')
+    expect(routeUpdate).toHaveBeenCalledTimes(1)
     await router.push('/foo')
+    expect(routeUpdate).toHaveBeenCalledTimes(1)
     await router.push('/foo?q')
-    expect(spy).toHaveBeenCalledTimes(2)
+    expect(routeUpdate).toHaveBeenCalledTimes(2)
+  })
+
+  // NOTE: this one seems to always pass on unit test, so we are using the e2e
+  // suspense test as well
+  it('works with async setup', async () => {
+    const { spy: normalSpy, Component } = withSpy()
+    const { spy: asyncSpy, Component: Async } = withSpy('Async', true)
+
+    const { router } = factory(
+      [
+        { path: '/', component: Component },
+        { path: '/async', component: Async },
+      ],
+      {
+        template: `<router-view v-slot="{ Component }">
+        <Suspense>
+          <component :is="Component" />
+        </Suspense>
+      </router-view>
+      `,
+      }
+    )
+
+    expect(normalSpy).toHaveBeenCalledTimes(0)
+    expect(asyncSpy).toHaveBeenCalledTimes(0)
+
+    await router.push('/async')
+    expect(normalSpy).toHaveBeenCalledTimes(0)
+    expect(asyncSpy).toHaveBeenCalledTimes(0)
+
+    await router.push({ query: { n: 1 } })
+    expect(normalSpy).toHaveBeenCalledTimes(0)
+    expect(asyncSpy).toHaveBeenCalledTimes(1)
+    expect(asyncSpy).toHaveBeenLastCalledWith(
+      expect.objectContaining({ fullPath: '/async?n=1' }),
+      expect.objectContaining({ fullPath: '/async' }),
+      expect.anything()
+    )
+
+    await router.push('/')
+    expect(normalSpy).toHaveBeenCalledTimes(0)
+    expect(asyncSpy).toHaveBeenCalledTimes(1)
+
+    await router.push({ query: { n: 2 } })
+    expect(normalSpy).toHaveBeenCalledTimes(1)
+    expect(normalSpy).toHaveBeenLastCalledWith(
+      expect.objectContaining({ fullPath: '/?n=2' }),
+      expect.objectContaining({ fullPath: '/' }),
+      expect.anything()
+    )
+
+    expect(asyncSpy).toHaveBeenCalledTimes(1)
+
+    await router.push('/async')
+    expect(normalSpy).toHaveBeenCalledTimes(1)
+    expect(asyncSpy).toHaveBeenCalledTimes(1)
   })
 })
index b51ddbdf2d647e786e1670f30447acc63a09ac91..d017b559b650232c010319c36bd47729381ede55 100644 (file)
@@ -31,6 +31,8 @@ export async function ticks(n: number) {
   }
 }
 
+export const delay = (t: number) => new Promise(r => setTimeout(r, t))
+
 export function nextNavigation(router: Router) {
   return new Promise((resolve, reject) => {
     let removeAfter = router.afterEach((_to, _from, failure) => {