10

In my component , I have a method which will execute a router.push()

import router from "@/router";
// ...
export default {
  // ...
  methods: {
    closeAlert: function() {
      if (this.msgTypeContactForm == "success") {
        router.push("/home");
      } else {
        return;
      }
    },
    // ....
  }
}

I want to test it...

I wrote the following specs..

it("should ... go to home page", async () => {
    // given
    const $route = {
      name: "home"
    },
    options = {
      ...
      mocks: {
        $route
      }
    };
    wrapper = mount(ContactForm, options);
    const closeBtn = wrapper.find(".v-alert__dismissible");
    closeBtn.trigger("click");
    await wrapper.vm.$nextTick();
    expect(alert.attributes().style).toBe("display: none;")
    // router path '/home' to be called ?
  });

1 - I get an error

console.error node_modules/@vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: could not overwrite property $route, this is usually caused by a plugin that has added the property asa read-only value

2 - How I should write the expect() to be sure that this /home route has been called

thanks for feedback

vahdet
  • 6,357
  • 9
  • 51
  • 106

2 Answers2

13

You are doing something that happens to work, but I believe is wrong, and also is causing you problems to test the router. You're importing the router in your component:

import router from "@/router";

Then calling its push right away:

router.push("/home");

I don't know how exactly you're installing the router, but usually you do something like:

new Vue({
  router,
  store,
  i18n,
}).$mount('#app');

To install Vue plugins. I bet you're already doing this (in fact, is this mechanism that expose $route to your component). In the example, a vuex store and a reference to vue-i18n are also being installed.

This will expose a $router member in all your components. Instead of importing the router and calling its push directly, you could call it from this as $router:

this.$router.push("/home");

Now, thise makes testing easier, because you can pass a fake router to your component, when testing, via the mocks property, just as you're doing with $route already:

  const push = jest.fn();
  const $router = {
    push: jest.fn(),
  }
  ...
  mocks: {
    $route,
    $router,
  }

And then, in your test, you assert against push having been called:

  expect(push).toHaveBeenCalledWith('/the-desired-path');
Sergeon
  • 6,638
  • 2
  • 23
  • 43
  • You are right ... I installed the router as you mentioned... and I understand better why I could not mock the router ... !! thanks a lot I am going to test it now .. How $route should be defined ? –  Nov 14 '18 at 17:59
  • 1
    i still get `[vue-test-utils]: could not overwrite property $route, this is usually caused by a plugin that has added the property asa read-only value` error – vaasav kumar Dec 07 '20 at 10:15
2

Assuming that you have setup the pre-requisities correctly and similar to this

Just use

it("should ... go to home page", async () => {
    const $route = {
      name: "home"
    }

  ...

  // router path '/home' to be called ?
  expect(wrapper.vm.$route.name).toBe($route.name)
});
Ru Chern Chong
  • 3,692
  • 13
  • 33
  • 43
  • thanks a lot ... it works with : expect(wrapper.vm.$route.name).toBe($route.name) ... not $rout.path –  Nov 15 '18 at 06:58
  • 1
    Oops, sorry. The `$route.path` was what I have used and a muscle memory. I hope this have helped you – Ru Chern Chong Nov 15 '18 at 07:00