Refactoring options api to use vue-router/composables break basic unit tests #3802
Description
Version
3.6.5
Reproduction link
Steps to reproduce
- Giving a basic options API component
<!-- using options API --> <template> <div>{{ msg }}</div> </template> <script> export default { computed: { msg() { return `My route name is ${this.$route.name}`; } } }; </script>
- refactoring to composition api
<!-- Refactoring using composition-api --> <script> import { useRoute } from 'vue-router/composables'; import { computed } from 'vue'; export default { setup() { const $route = useRoute(); const msg = computed(() => { `My route name is ${$route.name}`; }); return { msg, }; }, }; </script>
- The test that worked before, now breaks.
import { mount } from '@vue/test-utils'; import SomeComponent from './SomeComponent.vue'; const $route = { path: '/some/path', }; function Wrapper() { return mount(SomeComponent, { mocks: { $route, }, }); } test('mount component', () => { const wrapper = Wrapper(); expect(wrapper.exists()).toBe(true); // TypeError: Cannot read properties of undefined (reading 'currentRoute') });
What is expected?
using options/composition-api should not affect the test suite output
What is actually happening?
Using options/composition-api requires different ways to test (mock)
Additional Comments
Link to reproduction with same component written in "options API" mode
https://stackblitz.com/edit/vitejs-vite-rdjvxj?file=src%2Fviews%2FAbout.test.js
Heya! 👋
While I was waiting for the 3.6.x
release, I rolled some in-house vue-router hooks as per #3760 (comment). This allowed refactoring some options-API components to composition-api "mode" while keeping my test suite intact.
I thought the refactor to use the official package hooks would be a simple find/replace but my test suite broke. After some digging, the reason is that the hooks implementation relies on router.currentRoute
property and afterEach
hook, which made the tests using the simplest $route mock as suggested in vue-test-utils docs to fail.
Of course there's several ways to fix it: updating the test mocks as below; setting up a router with localVue as per docs; stubbing modules jest.mock()
; etc;
import { mount } from '@vue/test-utils';
import SomeComponent from './SomeComponent.vue';
const $route = {
path: '/some/path',
};
function Wrapper() {
return mount(SomeComponent, {
mocks: {
- $route,
+ $router: { currentRoute: $route, afterEach: vitest.fn() },
},
});
}
Question
If you went this way1, I'm sure there are good reasons for it. I'm just curious on why didn't you go with a similar approach as vue-router@4, as in, with a reactive object derived from getCurrentInstance().proxy.$route
as per2 which kept tests working without any change — but surely break some other stuff.
Cheers and thanks for your work on the router! Feel free to close this if you think it's related with @vue/test-utils
docs instead ✌️