pmrotule
pmrotule

Reputation: 9692

Can't mock module import in Cypress Vue component tests

I'm new to Cypress component testing, but I was able to set it up easily for my Vue project. I'm currently investigating if we should replace Jest with Cypress to test our Vue components and I love it so far, there is only one major feature I'm still missing: mocking modules. I first tried with cy.stub(), but it simply didn't work which could make sense since I'm not trying to mock the actual module in Node.js, but the module imported within Webpack.

To solve the issue, I tried to use rewiremock which is able to mock Webpack modules, but I'm getting an error when running the test:

enter image description here

I forked the examples from Cypress and set up Rewiremock in this commit. Not sure what I'm doing wrong to be honest.

I really need to find a way to solve it otherwise, we would simply stop considering Cypress and just stick to Jest. If using Rewiremock is not the way, how am I suppose to achieve this? Any help would be greatly appreciated.

Upvotes: 2

Views: 2067

Answers (2)

jchi2241
jchi2241

Reputation: 2226

We solved this by using webpack aliases in the Cypress webpack config to intercept the node_module dependency.

So something like...

// cypress/plugins/index.js

const path = require("path");
const { startDevServer } = require('@cypress/webpack-dev-server');

// your project's base webpack config
const webpackConfig = require('@vue/cli-service/webpack.config');

module.exports = (on, config) => {
  on("dev-server:start", (options) => {
    webpackConfig.resolve.alias["your-module"] = path.resolve(__dirname, "path/to/your-module-mock.js");

    return startDevServer({
      options,
      webpackConfig,
    })
  });
}
// path/to/your-module-mock.js

let yourMock;

export function setupMockModule(...) {
  yourMock = {
    ...
  };
}

export default yourMock;
// your-test.spec.js

import { setupMock } from ".../your-module-mock.js"

describe("...", () => {
  before(() => {
    setupMock(...);
  });

  it("...", () => {
    ...
  });
});

Upvotes: 0

Richard Matsen
Richard Matsen

Reputation: 23463

If you are able to adjust the Vue component to make it more testable, the function can be mocked as a component property.

Webpack

When vue-loader processes HelloWorld.vue, it evaluates getColorOfFruits() and sets the data property, so to mock the function here, you need a webpack re-writer like rewiremock.

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      colorOfFruits: getColorOfFruits(),   // during compile time
    };
  },
  ...

Vue created hook

If you initiialize colorOfFruits in the created() hook, you can stub the getColorOfFruits function after import but prior to mounting.

HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ colorOfFruits.apple }}</h2>
    <p>
    ...
</template>

<script lang="ts">
import { getColorOfFruits } from "@/helpers/fruit.js";  

export default {
  name: "HelloWorld",
  getColorOfFruits,          // add this function to the component for mocking
  props: {
    msg: String,
  },
  data() {
    return {
      colorOfFruits: {}      // initialized empty here
    };
  },
  created() {
    this.colorOfFruits = this.$options.colorOfFruits;  // reference function saved above
  }
});
</script>

HelloWorld.spec.js

import { mount } from "@cypress/vue";
import HelloWorld from "./HelloWorld.vue";

it("mocks an apple", () => {

  const getMockFruits = () => {
    return {
      apple: "green",
      orange: "purple",
    }
  }

  HelloWorld.getColorOfFruits = getMockFruits;

  mount(HelloWorld, {                      // created() hook called as part of mount()
    propsData: {
      msg: "Hello Cypress!",
    },
  });

  cy.get("h1").contains("Hello Cypress!");

  cy.get("h2").contains('green')

});

Upvotes: 2

Related Questions