Notoriously Punctual Manatee

    This package has been deprecated

    Author message:

    Please move to use @cypress/vue

    cypress-vue-unit-test
    TypeScript icon, indicating that this package has built-in type declarations

    3.5.1 • Public • Published

    cypress-vue-unit-test

    NPM

    Build status Cypress dashboard semantic-release renovate-app badge

    A little helper to unit test Vue components in the open source Cypress.io E2E test runner v4.5.0+

    Jump to: Comparison, Blog posts, Examples: basic, advanced, full, external, Code coverage

    TLDR

    • What is this? This package allows you to use Cypress test runner to unit test your Vue components with zero effort.

    Example component test

    • How is this different from vue-test-utils? Vue Test Utils uses Node, requires stubbing browser APIs, and requires users to await Vue's internal event loop. Cypress Vue Unit Test runs each component in the real browser with full power of Cypress E2E test runner: live GUI, full API, screen recording, CI support, cross-platform.

    • If you like using @testing-library/vue, you can use @testing-library/cypress for the same findBy, queryBy commands, see one of the examples in the list below

    Blog posts

    Install

    Terminal typing vue add cypress-experimental

    Vue CLI Installation

    Vue CLI v3+

    Recommended: One step install to existing projects with Vue CLI via experimental plugin, read Write Your First Vue Component Test

    vue add cypress-experimental

    If you want to install this package manually, follow manual install

    Usage and Examples

    // components/HelloWorld.spec.js
    import { mount } from 'cypress-vue-unit-test'
    import { HelloWorld } from './HelloWorld.vue'
    describe('HelloWorld component', () => {
      it('works', () => {
        mount(HelloWorld)
        // now use standard Cypress commands
        cy.contains('Hello World!').should('be.visible')
      })
    })

    Options

    You can pass additional styles, css files and external stylesheets to load, see docs/styles.md for full list.

    import Todo from './Todo.vue'
    const todo = {
      id: '123',
      title: 'Write more tests',
    }
     
    mount(Todo, {
      propsData: { todo },
      stylesheets: [
        'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css',
      ],
    })

    See examples below for details.

    Global Vue Options

    You can pass extensions (global components, mixins, modules to use) when mounting Vue component. Use { extensions: { ... }} object inside the options.

    • components - object of 'id' and components to register globally, see Components example
    • use (alias plugins) - list of plugins, see Plugins
    • mixin (alias mixins) - list of global mixins, see Mixins example
    • filters - hash of global filters, see Filters example

    The intro example

    Take a look at the first Vue v2 example: Declarative Rendering. The code is pretty simple

    <div id="app">
      {{ message }}
    </div>
    var app = new Vue({
      el: '#app',
      data() {
        return { message: 'Hello Vue!' }
      },
    })

    It shows the message when running in the browser

    Hello Vue!
    

    Let's test it in Cypress.io (for the current version see cypress/integration/spec.js).

    import { mountCallback } from 'cypress-vue-unit-test'
     
    describe('Declarative rendering', () => {
      // Vue code from https://vuejs.org/v2/guide/#Declarative-Rendering
      const template = `
        <div id="app">
          {{ message }}
        </div>
      `
     
      const data = {
        message: 'Hello Vue!',
      }
     
      // that's all you need to do
      beforeEach(mountCallback({ template, data }))
     
      it('shows hello', () => {
        cy.contains('Hello Vue!')
      })
     
      it('changes message if data changes', () => {
        // mounted Vue instance is available under Cypress.vue
        Cypress.vue.message = 'Vue rocks!'
        cy.contains('Vue rocks!')
      })
    })

    Fire up Cypress test runner and have real browser (Electron, Chrome) load Vue and mount your test code and be able to interact with the instance through the reference Cypress.vue.$data and via GUI. The full power of the Cypress API is available.

    Hello world tested

    The list example

    There is a list example next in the Vue docs.

    <div id="app-4">
      <ol>
        <li v-for="todo in todos">
          {{ todo.text }}
        </li>
      </ol>
    </div>
    var app4 = new Vue({
      el: '#app-4',
      data: {
        todos: [
          { text: 'Learn JavaScript' },
          { text: 'Learn Vue' },
          { text: 'Build something awesome' },
        ],
      },
    })

    Let's test it. Simple.

    import { mountCallback } from 'cypress-vue-unit-test'
     
    describe('Declarative rendering', () => {
      // List example from https://vuejs.org/v2/guide/#Declarative-Rendering
      const template = `
        <ol>
          <li v-for="todo in todos">
            {{ todo.text }}
          </li>
        </ol>
      `
     
      function data() {
        return {
          todos: [
            { text: 'Learn JavaScript' },
            { text: 'Learn Vue' },
            { text: 'Build something awesome' },
          ],
        }
      }
     
      beforeEach(mountCallback({ template, data }))
     
      it('shows 3 items', () => {
        cy.get('li').should('have.length', 3)
      })
     
      it('can add an item', () => {
        Cypress.vue.todos.push({ text: 'Test using Cypress' })
        cy.get('li').should('have.length', 4)
      })
    })

    List tested

    Handling User Input

    The next section in the Vue docs starts with reverse message example.

    <div id="app-5">
      <p>{{ message }}</p>
      <button v-on:click="reverseMessage">Reverse Message</button>
    </div>
    var app5 = new Vue({
      el: '#app-5',
      data: {
        message: 'Hello Vue.js!',
      },
      methods: {
        reverseMessage: function () {
          this.message = this.message.split('').reverse().join('')
        },
      },
    })

    We can write the test the same way

    import { mountCallback } from 'cypress-vue-unit-test'
     
    describe('Handling User Input', () => {
      // Example from https://vuejs.org/v2/guide/#Handling-User-Input
      const template = `
        <div>
          <p>{{ message }}</p>
          <button v-on:click="reverseMessage">Reverse Message</button>
        </div>
      `
     
      function data() {
        return { message: 'Hello Vue.js!' }
      }
     
      const methods = {
        reverseMessage: function () {
          this.message = this.message.split('').reverse().join('')
        },
      }
     
      beforeEach(mountCallback({ template, data, methods }))
     
      it('reverses text', () => {
        cy.contains('Hello Vue')
        cy.get('button').click()
        cy.contains('!sj.euV olleH')
      })
    })

    Take a look at the video of the test. When you hover over the CLICK step the test runner is showing before and after DOM snapshots. Not only that, the application is fully functioning, you can interact with the application because it is really running!

    Reverse input

    Component example

    Let us test a complex example. Let us test a single file Vue component. Here is the Hello.vue file

    <template>
      <p>{{ greeting }} World!</p>
    </template>
     
    <script>
    export default {
      data() {
        return {
          greeting: 'Hello',
        }
      },
    }
    </script>
     
    <style scoped>
    p {
      font-size: 2em;
      text-align: center;
    }
    </style>

    note to learn how to load Vue component files in Cypress, see Bundling section.

    Do you want to interact with the component? Go ahead! Do you want to have multiple components? No problem!

    import Hello from '../../components/Hello.vue'
    import { mountCallback } from 'cypress-vue-unit-test'
    describe('Several components', () => {
      const template = `
        <div>
          <hello></hello>
          <hello></hello>
          <hello></hello>
        </div>
      `
      const components = {
        hello: Hello,
      }
      beforeEach(mountCallback({ template, components }))
     
      it('greets the world 3 times', () => {
        cy.get('p').should('have.length', 3)
      })
    })

    Spying example

    Button counter component is used in several Vue doc examples

    <template>
      <button v-on:click="incrementCounter">{{ counter }}</button>
    </template>
     
    <script>
    export default {
      data() {
        return {
          counter: 0,
        }
      },
     
      methods: {
        incrementCounter: function () {
          this.counter += 1
          this.$emit('increment')
        },
      },
    }
    </script>
     
    <style scoped>
    button {
      margin: 5px 10px;
      padding: 5px 10px;
      border-radius: 3px;
    }
    </style>

    Let us test it - how do we ensure the event is emitted when the button is clicked? Simple - let us spy on the event, spying and stubbing is built into Cypress

    import ButtonCounter from '../../components/ButtonCounter.vue'
    import { mountCallback } from 'cypress-vue-unit-test'
     
    describe('ButtonCounter', () => {
      beforeEach(mountCallback(ButtonCounter))
     
      it('starts with zero', () => {
        cy.contains('button', '0')
      })
     
      it('increments the counter on click', () => {
        cy.get('button').click().click().click().contains('3')
      })
     
      it('emits "increment" event on click', () => {
        const spy = cy.spy()
        Cypress.vue.$on('increment', spy)
        cy.get('button')
          .click()
          .click()
          .then(() => {
            expect(spy).to.be.calledTwice
          })
      })
    })

    The component is really updating the counter in response to the click and is emitting an event.

    Spying test

    XHR spying and stubbing

    The mount function automatically wraps XMLHttpRequest giving you an ability to intercept XHR requests your component might do. For full documentation see Network Requests. In this repo see components/AjaxList.vue and the corresponding tests cypress/integration/ajax-list-spec.js.

    // component use axios to get list of users
    created() {
      axios.get(`https://jsonplaceholder.cypress.io/users?_limit=3`)
      .then(response => {
        // JSON responses are automatically parsed.
        this.users = response.data
      })
    }
    // test can observe, return mock data, delay and a lot more
    beforeEach(mountCallback(AjaxList))
    it('can inspect real data in XHR', () => {
      cy.server()
      cy.route('/users?_limit=3').as('users')
      cy.wait('@users').its('response.body').should('have.length', 3)
    })
    it('can display mock XHR response', () => {
      cy.server()
      const users = [{id: 1, name: 'foo'}]
      cy.route('GET', '/users?_limit=3', users).as('users')
      cy.get('li').should('have.length', 1)
        .first().contains('foo')
    })

    Spying on window.alert

    Calls to window.alert are automatically recorded, but do not show up. Instead you can spy on them, see AlertMessage.vue and its test cypress/integration/alert-spec.js

    Comparison

    Feature Vue Test Utils or @testing-library/vue Cypress + cypress-vue-unit-test
    Test runs in real browser
    Uses full mount
    Test speed 🏎 as fast as the app works in the browser
    Test can use additional plugins maybe use any Cypress plugin
    Test can interact with component synthetic limited API use any Cypress command
    Test can be debugged via terminal and Node debugger use browser DevTools
    Built-in time traveling debugger Cypress time traveling debugger
    Re-run tests on file or test change
    Test output on CI terminal terminal, screenshots, videos
    Tests can be run in parallel ✅ via parallelization
    Test against interface if using @testing-library/vue ✅ and can use @testing-library/cypress
    Spying and mocking Jest mocks Sinon library
    Code coverage

    Examples

    // components/HelloWorld.spec.js
    import { mount } from 'cypress-vue-unit-test'
    import { HelloWorld } from './HelloWorld.vue'
    describe('HelloWorld component', () => {
      it('works', () => {
        mount(HelloWorld)
        // now use standard Cypress commands
        cy.contains('Hello World!').should('be.visible')
      })
    })

    Basic examples

    Spec Description
    Components Registers global components to use
    Filters Registering global filters
    Hello Testing examples from Vue2 cookbook
    Mixins Registering Vue mixins
    Plugins Loading additional plugins
    Props Pass props to the component during mount
    Slots Passing slots and scopedSlots to the component
    Small examples A few small examples testing forms, buttons

    Advanced examples

    Spec Description
    access-component Access the mounted component directly from test
    i18n Testing component that uses Vue I18n plugin
    mocking-axios Mocking 3rd party CommonJS modules like axios
    mocking-fetch Mocking window.fetch to stub responses and test the UI
    fetch-polyfill Using experimental fetch polyfill to spy on / stub those Ajax requests using regular Cypress network methods
    mocking-components Mocking locally registered child components during tests
    mocking-imports Stub ES6 imports from the tests
    render-functions Mounting components with a render function

    Full examples

    We have several subfolders in examples folder.

    Folder Name Description
    cli An example app scaffolded using Vue CLI and the component testing added using vue add cypress-experimental command.

    External examples

    Repo Description
    vue-component-test-example Scaffolded Vue CLI v3 project with added component tests, read Write Your First Vue Component Test.

    Known problems

    Bundling

    How do we load this Vue file into the testing code? Using webpack preprocessor. Note that this module ships with @cypress/webpack-preprocessor 2.x that requires Webpack 4.x. If you have Webpack 3.x please add @cypress/webpack-preprocessor v1.x.

    Short way

    For Webpack Users

    Your project probably already has webpack.config.js setup to transpile .vue files. To load these files in the Cypress tests, grab the webpack processor included in this module, and load it from the cypress/plugins/index.js file.

    const {
      onFilePreprocessor,
    } = require('cypress-vue-unit-test/preprocessor/webpack')
    module.exports = (on) => {
      on('file:preprocessor', onFilePreprocessor('../path/to/webpack.config'))
    }

    Cypress should be able to import .vue files in the tests

    Manual

    Using @cypress/webpack-preprocessor and vue-loader. You can use cypress/plugins/index.js to load .vue files using vue-loader.

    // cypress/plugins/index.js
    const webpack = require('@cypress/webpack-preprocessor')
    const webpackOptions = {
      module: {
        rules: [
          {
            test: /\.vue$/,
            loader: 'vue-loader',
          },
        ],
      },
    }
     
    const options = {
      // send in the options from your webpack.config.js, so it works the same
      // as your app's code
      webpackOptions,
      watchOptions: {},
    }
     
    module.exports = (on) => {
      on('file:preprocessor', webpack(options))
    }

    Install dev dependencies

    npm i -D @cypress/webpack-preprocessor \
      vue-loader vue-template-compiler css-loader

    And write a test

    import Hello from '../../components/Hello.vue'
    import { mountCallback } from 'cypress-vue-unit-test'
     
    describe('Hello.vue', () => {
      beforeEach(mountCallback(Hello))
     
      it('shows hello', () => {
        cy.contains('Hello World!')
      })
    })

    Code coverage

    This plugin uses babel-plugin-istanbul to automatically instrument .js and .vue files and generates the code coverage report using dependency cypress-io/code-coverage (included). The output reports are saved in the folder "coverage" at the end of the test run.

    If you want to disable code coverage instrumentation and reporting, use --env coverage=false or CYPRESS_coverage=false or set in your cypress.json file

    {
      "env": {
        "coverage": false
      }
    }

    Development

    To see all local tests, install dependencies, build the code and open Cypress in GUI mode

    npm install
    npm run build
    npm run cy:open

    The build is done using tsc that transpiles all files from src to dist folder.

    Debugging

    Run Cypress with environment variable

    DEBUG=cypress-vue-unit-test
    

    If some deeply nested objects are abbreviated and do not print fully, set the maximum logging depth

    DEBUG=cypress-vue-unit-test DEBUG_DEPTH=10
    

    FAQ

    • If your component's static assets are not loading, you probably need to start and proxy Webpack dev server. See issue #4

    Related info

    Migration guide

    From v2 to v3

    • update cypress/plugins/index.js file to pass the on, config arguments when creating the default preprocessor. See change, in general the new way is:
    const {
      onFileDefaultPreprocessor,
    } = require('cypress-vue-unit-test/preprocessor/webpack')
     
    module.exports = (on, config) => {
      require('@cypress/code-coverage/task')(on, config)
      on('file:preprocessor', onFileDefaultPreprocessor(config))
     
      // IMPORTANT to return the config object
      // with the any changed environment variables
      return config
    }

    Test adapters for other frameworks

    Contributors

    Small print

    Author: Gleb Bahmutov <gleb.bahmutov@gmail.com> © 2017

    License: MIT - do anything with the code, but don't blame me if it does not work.

    Support: if you find any problems with this module, email / tweet / open issue on Github

    MIT License

    Copyright (c) 2017 Gleb Bahmutov <gleb.bahmutov@gmail.com>

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    Keywords

    Install

    npm i cypress-vue-unit-test

    DownloadsWeekly Downloads

    1,441

    Version

    3.5.1

    License

    MIT

    Unpacked Size

    49.4 kB

    Total Files

    12

    Last publish

    Collaborators

    • bahmutov