From c89447ad8f30ac646b421d3eeafcfac3e3fad7d4 Mon Sep 17 00:00:00 2001 From: cexbrayat Date: Mon, 11 Jan 2021 14:55:34 +0100 Subject: [PATCH 1/2] feat: setQuery --- README.md | 15 +++++++++ __tests__/navigations.spec.ts | 2 +- __tests__/params.spec.ts | 61 +++++++++++++++++++++++++---------- src/router.ts | 15 +++++++++ 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6cf51cb..825a413 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,21 @@ it('should display the user details', async () => { }) ``` +It can be awaited if you need to wait for Vue to render again: + +```js +it('should display the user details', async () => { + const wrapper = mount(UserDetails) + await getRouter().setParams({ userId: 12 }) + + // test... +}) +``` + +`setQuery` is very similar. +It can be used to set the route query without triggering a navigation, +and can be awaited too. + ### Setting the initial location By default the router mock starts on [`START_LOCATION`](https://next.router.vuejs.org/api/#start-location). In some scenarios this might need to be adjusted by pushing a new location and awaiting it before testing: diff --git a/__tests__/navigations.spec.ts b/__tests__/navigations.spec.ts index fc06e5a..1ef0089 100644 --- a/__tests__/navigations.spec.ts +++ b/__tests__/navigations.spec.ts @@ -198,7 +198,7 @@ describe('Navigations', () => { expect(wrapper.text()).toBe('/bar') }) - it.skip('can wait for an ongoing navigation', async () => { + it('can wait for an ongoing navigation', async () => { const wrapper = mount(Test) const router = getRouter() diff --git a/__tests__/params.spec.ts b/__tests__/params.spec.ts index 3b526df..4219e3b 100644 --- a/__tests__/params.spec.ts +++ b/__tests__/params.spec.ts @@ -2,27 +2,54 @@ import { mount } from '@vue/test-utils' import { watch } from 'vue' import { getRouter } from '../src' -describe('setParams', () => { - it('sets current route params', async () => { - const router = getRouter() - router.setParams({ userId: 12 }) - const wrapper = mount({ - template: `

{{ $route.params.userId }}

`, +describe('Params utils', () => { + describe('`setParams`', () => { + it('sets current route params', async () => { + const router = getRouter() + router.setParams({ userId: 12 }) + const wrapper = mount({ + template: `

{{ $route.params.userId }}

`, + }) + const spy = jest.fn() + + watch(wrapper.vm.$route, spy) + + expect(wrapper.vm.$route.params).toEqual({ userId: '12' }) + expect(wrapper.text()).toBe('12') + expect(spy).toHaveBeenCalledTimes(0) + + await router.setParams({ userId: 12 }) + expect(spy).toHaveBeenCalledTimes(1) + expect(wrapper.text()).toBe('12') + + await router.setParams({ userId: 2 }) + expect(spy).toHaveBeenCalledTimes(2) + expect(wrapper.text()).toBe('2') }) - const spy = jest.fn() + }) + + describe('`setQuery`', () => { + it('sets current route query', async () => { + const router = getRouter() + router.setQuery({ page: 2 }) + const wrapper = mount({ + template: `

{{ $route.query.page }}

`, + }) + const spy = jest.fn() - watch(wrapper.vm.$route, spy) + watch(wrapper.vm.$route, spy) - expect(wrapper.vm.$route.params).toEqual({ userId: '12' }) - expect(wrapper.text()).toBe('12') - expect(spy).toHaveBeenCalledTimes(0) + expect(wrapper.vm.$route.query).toEqual({ page: '2' }) + expect(wrapper.text()).toBe('2') + expect(spy).toHaveBeenCalledTimes(0) - await router.setParams({ userId: 12 }) - expect(spy).toHaveBeenCalledTimes(1) - expect(wrapper.text()).toBe('12') + await router.setQuery({ page: 2 }) + expect(spy).toHaveBeenCalledTimes(1) + expect(wrapper.text()).toBe('2') - await router.setParams({ userId: 2 }) - expect(spy).toHaveBeenCalledTimes(2) - expect(wrapper.text()).toBe('2') + await router.setQuery({ page: 3 }) + expect(spy).toHaveBeenCalledTimes(2) + expect(wrapper.text()).toBe('3') + }) }) }) diff --git a/src/router.ts b/src/router.ts index 74b67c9..1d6cab8 100644 --- a/src/router.ts +++ b/src/router.ts @@ -2,6 +2,7 @@ import { Component, nextTick, Ref, ref } from 'vue' import { createMemoryHistory, createRouter, + LocationQueryRaw, RouteLocationRaw, RouteParamsRaw, Router, @@ -49,6 +50,14 @@ export interface RouterMock extends Router { * @param params - params to set in the current route */ setParams(params: RouteParamsRaw): void + + /** + * Sets the query of the current route without triggering a navigation. Can + * be awaited to wait for Vue to render again. + * + * @param query - query to set in the current route + */ + setQuery(query: LocationQueryRaw): void } export interface RouterMockOptions extends Partial { @@ -188,6 +197,11 @@ export function createRouterMock(options: RouterMockOptions = {}): RouterMock { return nextTick() } + function setQuery(query: LocationQueryRaw) { + router.currentRoute.value = router.resolve({ query }) + return nextTick() + } + const depth = ref(0) return { @@ -196,5 +210,6 @@ export function createRouterMock(options: RouterMockOptions = {}): RouterMock { setNextGuardReturn, getPendingNavigation, setParams, + setQuery, } } From 0982c25c71850872acb4369e0c1c50a301d30177 Mon Sep 17 00:00:00 2001 From: cexbrayat Date: Mon, 11 Jan 2021 17:52:49 +0100 Subject: [PATCH 2/2] feat: setHash --- README.md | 4 +-- ...params.spec.ts => partialLocation.spec.ts} | 31 +++++++++++++++++-- src/router.ts | 18 +++++++++-- 3 files changed, 46 insertions(+), 7 deletions(-) rename __tests__/{params.spec.ts => partialLocation.spec.ts} (65%) diff --git a/README.md b/README.md index 825a413..7fc20d5 100644 --- a/README.md +++ b/README.md @@ -161,8 +161,8 @@ it('should display the user details', async () => { }) ``` -`setQuery` is very similar. -It can be used to set the route query without triggering a navigation, +`setQuery` and `setHash` are very similar. +They can be used to set the route query or hash without triggering a navigation, and can be awaited too. ### Setting the initial location diff --git a/__tests__/params.spec.ts b/__tests__/partialLocation.spec.ts similarity index 65% rename from __tests__/params.spec.ts rename to __tests__/partialLocation.spec.ts index 4219e3b..28f1cac 100644 --- a/__tests__/params.spec.ts +++ b/__tests__/partialLocation.spec.ts @@ -2,8 +2,8 @@ import { mount } from '@vue/test-utils' import { watch } from 'vue' import { getRouter } from '../src' -describe('Params utils', () => { - describe('`setParams`', () => { +describe('partial location', () => { + describe('setParams', () => { it('sets current route params', async () => { const router = getRouter() router.setParams({ userId: 12 }) @@ -28,7 +28,7 @@ describe('Params utils', () => { }) }) - describe('`setQuery`', () => { + describe('setQuery', () => { it('sets current route query', async () => { const router = getRouter() router.setQuery({ page: 2 }) @@ -52,4 +52,29 @@ describe('Params utils', () => { expect(wrapper.text()).toBe('3') }) }) + + describe('setHash', () => { + it('sets current route hash', async () => { + const router = getRouter() + router.setHash('#more') + const wrapper = mount({ + template: `

{{ $route.hash }}

`, + }) + const spy = jest.fn() + + watch(wrapper.vm.$route, spy) + + expect(wrapper.vm.$route.hash).toEqual('#more') + expect(wrapper.text()).toBe('#more') + expect(spy).toHaveBeenCalledTimes(0) + + await router.setHash('#more') + expect(spy).toHaveBeenCalledTimes(1) + expect(wrapper.text()).toBe('#more') + + await router.setHash('#about') + expect(spy).toHaveBeenCalledTimes(2) + expect(wrapper.text()).toBe('#about') + }) + }) }) diff --git a/src/router.ts b/src/router.ts index 1d6cab8..fbfbaf1 100644 --- a/src/router.ts +++ b/src/router.ts @@ -49,7 +49,7 @@ export interface RouterMock extends Router { * * @param params - params to set in the current route */ - setParams(params: RouteParamsRaw): void + setParams(params: RouteParamsRaw): Promise /** * Sets the query of the current route without triggering a navigation. Can @@ -57,7 +57,15 @@ export interface RouterMock extends Router { * * @param query - query to set in the current route */ - setQuery(query: LocationQueryRaw): void + setQuery(query: LocationQueryRaw): Promise + + /** + * Sets the hash of the current route without triggering a navigation. Can + * be awaited to wait for Vue to render again. + * + * @param hash - hash to set in the current route + */ + setHash(hash: string): Promise } export interface RouterMockOptions extends Partial { @@ -202,6 +210,11 @@ export function createRouterMock(options: RouterMockOptions = {}): RouterMock { return nextTick() } + function setHash(hash: string) { + router.currentRoute.value = router.resolve({ hash }) + return nextTick() + } + const depth = ref(0) return { @@ -211,5 +224,6 @@ export function createRouterMock(options: RouterMockOptions = {}): RouterMock { getPendingNavigation, setParams, setQuery, + setHash, } }