vue-router icon indicating copy to clipboard operation
vue-router copied to clipboard

Refactoring options api to use vue-router/composables break basic unit tests

Open renatodeleao opened this issue 1 year ago • 1 comments

Version

3.6.5

Reproduction link

stackblitz.com

Steps to reproduce

  1. 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>
    
  2. 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>
    
  3. 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 https://github.com/vuejs/vue-router/issues/3760#issuecomment-1191774443. 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 way^1, 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 per^2 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 ✌️

renatodeleao avatar Nov 01 '22 15:11 renatodeleao

Any mock to the router does indeed need a bit more if they use the composables. I think some cookbook entry would be a nice thing if anybody is up for the PR

I had to go with that version because [2] didn't work in all scenarios 😔

Ideally a Vue 2 version of https://github.com/posva/vue-router-mock would be perfect

posva avatar Nov 03 '22 19:11 posva