├── .browserslistrc ├── .gitignore ├── README.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── .keep ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── img1.png ├── img2.png ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.spec.ts ├── App.vue ├── LazyLoad.vue ├── assets │ └── logo.png ├── components │ ├── ClickToLazyLoad.spec.ts │ ├── ClickToLazyLoad.vue │ ├── HelloWorld.spec.ts │ └── HelloWorld.vue ├── main.ts ├── shims-tsx.d.ts └── shims-vue.d.ts ├── tsconfig.json └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | cypress/videos 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cypress Component Testing is here! Quickstart: 2 | 3 | 1. clone this repo 4 | 2. `yarn install` 5 | 3. `yarn cypress open-ct` 6 | 4. Write some tests! 7 | 8 | ## Getting Start with Cypress Component Testing (Vue 2/3) 9 | 10 | As of Cypress 7.0, the new Cpyress Component Testing Runner is now bundled with the Cypress! It takes inspiration and builds on the learnings from the original component testing implementation, which was hidden behind the `experimentalComponentTesting` flag. 11 | 12 | In this blog post we will see how to set up Cypress Component Testing with a Vue CLI project. It supports both Vue 2 and Vue 3, with TypeScript support out of the box. 13 | 14 | You can get the source code for the example used in the blog post [here](https://github.com/lmiller1990/vue-cypress-template). 15 | 16 | ## Creating a new Vue CLI Project 17 | 18 | Create a new Vue CLI project to get started. For this example I chose _Vue 2_ and _TypeScript_. 19 | 20 | ## Configuring Cypress Component Testing 21 | 22 | Once you've got a Vue project, you'll also need to install Cypress and the Webpack Dev Server and Vue adapters. Vue CLI projects are Webpack based; that's why we are installing the relevant Webpack adapter: 23 | 24 | 25 | ```sh 26 | # Vue 2 27 | yarn add cypress @cypress/vue @cypress/webpack-dev-server --dev 28 | 29 | # Vue 3 30 | npm install cypress @cypress/vue@next @cypress/webpack-dev-server --dev 31 | ``` 32 | 33 | Component Testing is configured as a [Cypress plugin](https://docs.cypress.io/guides/tooling/plugins-guide). This means you need to create a plugins file. By default this goes in `cypress/plugins/index.js`. 34 | 35 | Next, we need to register the `dev-server:start` event and tell Cypress to use the same Webpack configuration as the Vue CLI project uses. 36 | 37 | ```js 38 | const { startDevServer } = require('@cypress/webpack-dev-server') 39 | const webpackConfig = require('@vue/cli-service/webpack.config.js') 40 | 41 | module.exports = (on, config) => { 42 | on('dev-server:start', options => 43 | startDevServer({ 44 | options, 45 | webpackConfig 46 | }) 47 | ) 48 | 49 | return config 50 | } 51 | ``` 52 | 53 | Finally, we need to tell Cypress where and how to find our tests. Cypress is heavily configurable via `cypress.json`. My `cypress.json` looks as follows: 54 | 55 | ``` 56 | { 57 | "component": { 58 | "componentFolder": "src", 59 | "testFiles": "**/*.spec.ts" 60 | } 61 | } 62 | ``` 63 | 64 | All my comoponent are in `src`, and the spec files are always named `*.spec.ts`. 65 | 66 | ## Writing Some Tests 67 | 68 | It is finally time to write some tests. I created `src/components/HelloWorld.spec.ts` to try things out with the following minimal test: 69 | 70 | ```ts 71 | import { mount } from '@cypress/vue' 72 | import HelloWorld from './HelloWorld.vue' 73 | 74 | describe('HelloWorld', () => { 75 | it('renders a message', () => { 76 | const msg = 'Hello Cypress Component Testing!' 77 | mount(HelloWorld, { 78 | propsData: { 79 | msg 80 | } 81 | }) 82 | 83 | cy.get('h1').should('have.text', msg) 84 | }) 85 | }) 86 | ``` 87 | 88 | The `mount` function is very similar to the one from [Vue Test Utils](https://vue-test-utils.vuejs.org/). It's actually built on top of Vue Test Utils, so you can use the mounting options you might already be familiar with. 89 | 90 | Learn more about how to write assertions with Cypress [in the official docs](https://docs.cypress.io/guides/references/assertions). Get an overview of the `cy` object and how to use it [here](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress#Cypress-Can-Be-Simple-Sometimes). 91 | 92 | Finally, open the Component Testing runner: 93 | 94 | ```sh 95 | yarn cypress open-ct # or npx cypress open-ct 96 | ``` 97 | 98 | Select the spec and watch the test pass! 99 | 100 |  101 | 102 | Try updating the test and making it fail. Cypress will re-run your test (almost) instantly. This makes for a great red-green-refactor loop. 103 | 104 |  105 | 106 | ## Vue 3 Usage 107 | 108 | Everything works the same with Vue 3. Just make sure you have a Vue 3 project and the correct adapter: 109 | 110 | ```sh 111 | yarn add @cypress/vue@next --dev 112 | # or 113 | npm install @cypress/vue@next --dev 114 | ``` 115 | 116 | The `mount` function exported by `@cypress/vue` has the same API for both Vue 2 and Vue 3. The mounting options are the same as [Vue Test Utils](https://next.vue-test-utils.vuejs.org/api/#mount), so if you've used Vue Test Utils before, you'll feel right at home. 117 | 118 | ## Discussion 119 | 120 | Cypress Component Testing is an alternative to a jsdom based testing environment, such as Jest and Vue Test Utils. Cypress Component Testing offers many benefits: 121 | 122 | - Runs in a real browser. This means your tests are closer to what your users will be experiencing. 123 | - Visual. You can see exactly what is rendered. No more `console.log(wrapper.html())`. 124 | - Powered by Cypress - the most popular and reliable E2E testing tool out there. 125 | 126 | It also doubles as a *design environment*. You can see the component as you develop it, and hot reload give you a near instance feedback loop. It can potentially take the place of not only your Jest based test infrastructure, but your Storybook based design infrastructure as well. 127 | 128 | Cypress Component Testing is still in alpha but is quickly evolving and promises to change the landscape of Component Testing. 129 | 130 | ## Conclusion 131 | 132 | Cypress Component Testing brings everything that is great about Cypress to Component Testing. Since the underlying adapters are built on libraries like Webpack and Vue Test Utils, you don't need to throw away your entire test suite - incrementally migration is more than possible. 133 | 134 | The visual aspect united testing and design in a single tool. My days of grepping a messy console output to figure out what the user will see are over - I can see exactly what the component will look like as my tests run. 135 | 136 | You can get the source code for the example used in the blog post [here](https://github.com/lmiller1990/vue-cypress-template). 137 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": { 3 | "componentFolder": "src", 4 | "testFiles": "**/*.spec.ts" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /cypress/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmiller1990/vue-cypress-template/7b874342567448a6a1e445ac7c1c5bf41a9d11b0/cypress/integration/.keep -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | const { startDevServer } = require('@cypress/webpack-dev-server') 2 | const webpackConfig = require('@vue/cli-service/webpack.config.js') 3 | 4 | module.exports = (on, config) => { 5 | on('dev-server:start', options => 6 | startDevServer({ 7 | options, 8 | webpackConfig 9 | }) 10 | ) 11 | 12 | return config 13 | } 14 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmiller1990/vue-cypress-template/7b874342567448a6a1e445ac7c1c5bf41a9d11b0/img1.png -------------------------------------------------------------------------------- /img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmiller1990/vue-cypress-template/7b874342567448a6a1e445ac7c1c5bf41a9d11b0/img2.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cypress-template", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "vue": "^2.6.11" 11 | }, 12 | "devDependencies": { 13 | "@cypress/vue": "^2.2.0", 14 | "@cypress/webpack-dev-server": "^1.1.3", 15 | "@vue/cli-plugin-typescript": "~4.5.0", 16 | "@vue/cli-service": "~4.5.0", 17 | "cypress": "^7.0.0", 18 | "typescript": "~4.1.5", 19 | "vue-template-compiler": "^2.6.11" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmiller1990/vue-cypress-template/7b874342567448a6a1e445ac7c1c5bf41a9d11b0/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 |This is a test component to be loaded lazily with import('...')
3 | 4 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmiller1990/vue-cypress-template/7b874342567448a6a1e445ac7c1c5bf41a9d11b0/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/ClickToLazyLoad.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@cypress/vue' 2 | import ClickToLazyLoad from '@/components/ClickToLazyLoad.vue' 3 | 4 | describe('ClickToLazyLoad', () => { 5 | it('loads a component lazily when clicking a button', () => { 6 | mount(ClickToLazyLoad) 7 | cy.get('button').click() 8 | cy.get('p').should('have.text', `This is a test component to be loaded lazily with import('...')`) 9 | }) 10 | }) -------------------------------------------------------------------------------- /src/components/ClickToLazyLoad.vue: -------------------------------------------------------------------------------- 1 | 2 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |