├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── package.json
├── src
└── vue-jest-utils.ts
├── test
├── src
│ ├── counter-js.vue
│ ├── counter-ts.ts
│ └── counter-ts.vue
└── test
│ ├── __snapshots__
│ ├── counter-js.spec.js.snap
│ └── counter-ts.spec.ts.snap
│ ├── counter-js.spec.js
│ └── counter-ts.spec.ts
├── tsconfig.json
├── tsconfigDist.json
├── tslint.json
└── types
└── html2jade.d.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | /lib/
2 |
3 | # Created by https://www.gitignore.io/api/macos,windows,linux,visualstudiocode,webstorm,sublimetext,node,git
4 |
5 | ### macOS ###
6 | *.DS_Store
7 | .AppleDouble
8 | .LSOverride
9 |
10 | # Icon must end with two \r
11 | Icon
12 |
13 |
14 | # Thumbnails
15 | ._*
16 |
17 | # Files that might appear in the root of a volume
18 | .DocumentRevisions-V100
19 | .fseventsd
20 | .Spotlight-V100
21 | .TemporaryItems
22 | .Trashes
23 | .VolumeIcon.icns
24 | .com.apple.timemachine.donotpresent
25 |
26 | # Directories potentially created on remote AFP share
27 | .AppleDB
28 | .AppleDesktop
29 | Network Trash Folder
30 | Temporary Items
31 | .apdisk
32 |
33 |
34 | ### Windows ###
35 | # Windows image file caches
36 | Thumbs.db
37 | ehthumbs.db
38 |
39 | # Folder config file
40 | Desktop.ini
41 |
42 | # Recycle Bin used on file shares
43 | $RECYCLE.BIN/
44 |
45 | # Windows Installer files
46 | *.cab
47 | *.msi
48 | *.msm
49 | *.msp
50 |
51 | # Windows shortcuts
52 | *.lnk
53 |
54 |
55 | ### Linux ###
56 | *~
57 |
58 | # temporary files which can be created if a process still has a handle open of a deleted file
59 | .fuse_hidden*
60 |
61 | # KDE directory preferences
62 | .directory
63 |
64 | # Linux trash folder which might appear on any partition or disk
65 | .Trash-*
66 |
67 |
68 | ### VisualStudioCode ###
69 | .vscode/*
70 | !.vscode/settings.json
71 | !.vscode/tasks.json
72 | !.vscode/launch.json
73 |
74 |
75 | ### WebStorm ###
76 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
77 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
78 |
79 | # User-specific stuff:
80 | .idea/workspace.xml
81 | .idea/tasks.xml
82 | .idea/dictionaries
83 | .idea/vcs.xml
84 | .idea/jsLibraryMappings.xml
85 |
86 | # Sensitive or high-churn files:
87 | .idea/dataSources.ids
88 | .idea/dataSources.xml
89 | .idea/dataSources.local.xml
90 | .idea/sqlDataSources.xml
91 | .idea/dynamic.xml
92 | .idea/uiDesigner.xml
93 |
94 | # Gradle:
95 | .idea/gradle.xml
96 | .idea/libraries
97 |
98 | # Mongo Explorer plugin:
99 | .idea/mongoSettings.xml
100 |
101 | ## File-based project format:
102 | *.iws
103 |
104 | ## Plugin-specific files:
105 |
106 | # IntelliJ
107 | /out/
108 |
109 | # mpeltonen/sbt-idea plugin
110 | .idea_modules/
111 |
112 | # JIRA plugin
113 | atlassian-ide-plugin.xml
114 |
115 | # Crashlytics plugin (for Android Studio and IntelliJ)
116 | com_crashlytics_export_strings.xml
117 | crashlytics.properties
118 | crashlytics-build.properties
119 | fabric.properties
120 |
121 | ### WebStorm Patch ###
122 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
123 |
124 | # *.iml
125 | # modules.xml
126 | # .idea/misc.xml
127 | # *.ipr
128 |
129 |
130 | ### SublimeText ###
131 | # cache files for sublime text
132 | *.tmlanguage.cache
133 | *.tmPreferences.cache
134 | *.stTheme.cache
135 |
136 | # workspace files are user-specific
137 | *.sublime-workspace
138 |
139 | # project files should be checked into the repository, unless a significant
140 | # proportion of contributors will probably not be using SublimeText
141 | # *.sublime-project
142 |
143 | # sftp configuration file
144 | sftp-config.json
145 |
146 | # Package control specific files
147 | Package Control.last-run
148 | Package Control.ca-list
149 | Package Control.ca-bundle
150 | Package Control.system-ca-bundle
151 | Package Control.cache/
152 | Package Control.ca-certs/
153 | bh_unicode_properties.cache
154 |
155 | # Sublime-github package stores a github token in this file
156 | # https://packagecontrol.io/packages/sublime-github
157 | GitHub.sublime-settings
158 |
159 |
160 | ### Node ###
161 | /.npmrc
162 | # Logs
163 | logs
164 | *.log
165 | npm-debug.log*
166 |
167 | # Runtime data
168 | pids
169 | *.pid
170 | *.seed
171 | *.pid.lock
172 |
173 | # Directory for instrumented libs generated by jscoverage/JSCover
174 | lib-cov
175 |
176 | # Coverage directory used by tools like istanbul
177 | coverage
178 |
179 | # nyc test coverage
180 | .nyc_output
181 |
182 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
183 | .grunt
184 |
185 | # node-waf configuration
186 | .lock-wscript
187 |
188 | # Compiled binary addons (http://nodejs.org/api/addons.html)
189 | build/Release
190 |
191 | # Dependency directories
192 | node_modules
193 | jspm_packages
194 |
195 | # Optional npm cache directory
196 | .npm
197 |
198 | # Optional REPL history
199 | .node_repl_history
200 |
201 |
202 | ### Git ###
203 | *.orig
204 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | script: npm run prepublish
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Locoslab GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-jest-utils [](https://travis-ci.org/locoslab/vue-jest-utils) [](https://badge.fury.io/js/vue-jest-utils)
2 | Utilities for testing [Vue.js](http://vuejs.org/) components using [Jest](https://facebook.github.io/jest/).
3 |
4 | While written in TypeScript (and thus including type definitions), it can also be used in a pure JavaScript environment.
5 |
6 | Disclaimer: this project is currently very much work-in-progress. The motivating use case is simplifying snapshot testing using a combination of Vue.js, TypeScript, Jest, and html2jade. Additional functionality will be added as needed and breaking API changes may happen before releasing 1.0. Contributions are more than welcome.
7 |
8 | ## Usage
9 | Install: `npm install --save-dev vue-jest-utils`
10 |
11 | Note: Vue.js 2.0 and Jest must be installed as well.
12 |
13 | To use Jest with Vue.js single-file components (`*.vue`) or TypeScript sources, follow the guide on [vue-typescript-jest](https://github.com/locoslab/vue-typescript-jest).
14 |
15 | For a complete example of a TypeScript/Tsify/Vue.js/Vueify/Pug setup supporting Hot Module Replacement and unit/snapshot testing with Jest, cf. [vue-typescript-component-example](https://github.com/locoslab/vue-typescript-component-example).
16 |
17 |
18 | ### Examples
19 |
20 | #### JavaScript Test Example
21 | ```javascript
22 | const Vue = require('vue')
23 | const VJU = require('vue-jest-utils')
24 |
25 | const CounterJs = require('../src/counter-js.vue')
26 |
27 | describe('counter-js.vue', () => {
28 | it('should just work', () => {
29 | const vm = new Vue({
30 | el: document.createElement('div'),
31 | render: (h) => h(CounterJs),
32 | })
33 | VJU.clickNthButton(vm.$el, 1)
34 | VJU.clickNthButton(vm.$el, 3)
35 | VJU.clickNthButton(vm.$el, 2)
36 | // return a Promise that
37 | // 1. calls vm.nextTick()
38 | // 2. checks the snapshot of vm.$el using html2jade
39 | return VJU.expectToMatchSnapshot(vm)
40 | })
41 | })
42 | ```
43 |
44 | #### TypeScript Test Example
45 | ```typescript
46 | ///
47 |
48 | import Vue = require('vue')
49 | import {expectToMatchSnapshot, clickNthButton} from 'vue-jest-utils'
50 | import CounterTs = require('../src/counter-ts.vue')
51 |
52 | describe('counter-ts.vue', () => {
53 | it('should just work', () => {
54 | const vm = new Vue({
55 | el: document.createElement('div'),
56 | render: (h) => h(CounterTs),
57 | })
58 | clickNthButton(vm.$el, 1)
59 | clickNthButton(vm.$el, 3)
60 | clickNthButton(vm.$el, 2)
61 | // return a Promise that
62 | // 1. calls vm.nextTick()
63 | // 2. checks the snapshot of vm.$el using html2jade
64 | return expectToMatchSnapshot(vm)
65 | })
66 | })
67 | ```
68 |
69 | ## Contributing
70 | Contributions including bug reports, tests, and documentation are more than welcome. To get started with development:
71 | ``` bash
72 | # once: install dependencies
73 | npm install
74 |
75 | # run unit tests in watch mode
76 | npm test -- --watch
77 |
78 | # lint & test
79 | npm run prepublish
80 | ```
81 |
82 | ## License
83 | [MIT](http://opensource.org/licenses/MIT)
84 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-jest-utils",
3 | "version": "0.2.0",
4 | "description": "Utilities for using Jest with Vue.js",
5 | "author": "Locoslab GmbH",
6 | "homepage": "https://github.com/locoslab/vue-jest-utils",
7 | "bugs": "https://github.com/locoslab/vue-jest-utils/issues",
8 | "repository": "locoslab/vue-jest-utils",
9 | "license": "MIT",
10 | "main": "./lib/vue-jest-utils.js",
11 | "typings": "./lib/vue-jest-utils.d.ts",
12 | "files": [
13 | "lib"
14 | ],
15 | "keywords": [
16 | "vue",
17 | "jest",
18 | "typescript",
19 | "testing"
20 | ],
21 | "scripts": {
22 | "test": "jest",
23 | "lint": "tslint src/**/*.ts test/**/*.ts",
24 | "prepublish": "tslint src/**/*.ts && jest --coverage --no-cache && tsc -p tsconfigDist.json"
25 | },
26 | "jest": {
27 | "transform": {
28 | ".*\\.(ts|vue)$": "/node_modules/vue-typescript-jest/preprocessor.js"
29 | },
30 | "moduleFileExtensions": [
31 | "ts",
32 | "js",
33 | "vue"
34 | ],
35 | "testRegex": "/test/test/.*\\.(ts|js)$",
36 | "coveragePathIgnorePatterns": [
37 | "/node_modules/",
38 | "/test/.*\\.(ts|js)$",
39 | "/.*\\.vue$"
40 | ]
41 | },
42 | "babel": {
43 | "presets": [
44 | "es2015"
45 | ]
46 | },
47 | "peerDependencies": {
48 | "jest-cli": ">=16.0.0",
49 | "vue": "^2.0.1"
50 | },
51 | "dependencies": {
52 | "html2jade": "^0.8.5"
53 | },
54 | "devDependencies": {
55 | "@types/jest": "^19.0.0",
56 | "babel-core": "^6.0.0",
57 | "babel-plugin-transform-runtime": "^6.0.0",
58 | "babel-preset-es2015": "^6.0.0",
59 | "babel-runtime": "^6.0.0",
60 | "jest-cli": "^19.0.0",
61 | "pug": "^2.0.0-beta6",
62 | "tslint": "^5.1.0",
63 | "tslint-config-locoslab": "^1.0.0",
64 | "typescript": "^2.1.1",
65 | "vue": "^2.0.7",
66 | "vue-template-compiler": "^2.0.7",
67 | "vue-template-es2015-compiler": "^1.2.2",
68 | "vue-typescript-jest": "^0.3.0",
69 | "vue-typescript-import-dts": "^2.0.0"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/vue-jest-utils.ts:
--------------------------------------------------------------------------------
1 | import Html2jade = require('html2jade')
2 | import Vue = require('vue')
3 |
4 | /** convert html to pug as a Promise */
5 | export function html2pug(html: string) {
6 | return new Promise((resolve, reject) => {
7 | Html2jade.convertHtml(html, {bodyless: true}, (err: any, jade: string) => {
8 | if (err) {
9 | reject(err)
10 | } else {
11 | resolve(jade)
12 | }
13 | })
14 | })
15 | }
16 |
17 | /** call vm.nextTick() as a Promise */
18 | export function nextTick(vm: Vue) {
19 | return new Promise((resolve, reject) => {
20 | Vue.nextTick(() => resolve())
21 | })
22 | }
23 |
24 | /** call vm.nextTick() and check the snapshot as a Promise */
25 | export function expectToMatchSnapshot(vm: Vue, element?: HTMLElement) {
26 | return new Promise((resolve, reject) => {
27 | nextTick(vm).then(() => html2pug((element || vm.$el).innerHTML)).then((jade) => {
28 | expect(jade).toMatchSnapshot()
29 | resolve()
30 | }).catch((err)=>(reject(err)))
31 | })
32 | }
33 |
34 | /** click the nth button */
35 | export function clickNthButton(el: HTMLElement, n: number) {
36 | (el.querySelector('button:nth-of-type(' + n + ')') as HTMLButtonElement).click()
37 | }
38 |
--------------------------------------------------------------------------------
/test/src/counter-js.vue:
--------------------------------------------------------------------------------
1 |
2 | div(style='margin: 1em 1em')
3 | span(style='display:inline-block; width:6em') {{ name }}
4 | span(style='display:inline-block; width:3em; text-align: center') {{ counter }}
5 | button(href='#' v-on:click.stop='inc' style='display:inline-block; width:2em') +
6 | button(href='#' v-on:click.stop='dec' style='display:inline-block; width:2em') -
7 | button(href='#' v-on:click.stop='inverse=counter' style='display:inline-block; width:2em') !
8 | span(style='display:inline-block; width:3em; text-align: center') {{ inverse }}
9 |
10 |
11 |
42 |
--------------------------------------------------------------------------------
/test/src/counter-ts.ts:
--------------------------------------------------------------------------------
1 | const thisIsTypescript: string = 'counter-ts'
2 | export default {
3 | data () {
4 | return {
5 | name: thisIsTypescript,
6 | counter: 0
7 | }
8 | },
9 | methods: {
10 | inc: function() {
11 | this.counter++
12 | },
13 | dec: function() {
14 | this.counter--
15 | },
16 | uncoveredFunction: function() {
17 | this.counter *= 2
18 | }
19 | },
20 | computed: {
21 | inverse: {
22 | get: function() {
23 | return -this.counter
24 | },
25 | set: function(value: number) {
26 | this.counter = -value
27 | }
28 | },
29 | },
30 | created: function () {
31 | this.counter++
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/test/src/counter-ts.vue:
--------------------------------------------------------------------------------
1 |
2 | div(style='margin: 1em 1em')
3 | span(style='display:inline-block; width:6em') {{ name }}
4 | span(style='display:inline-block; width:3em; text-align: center') {{ counter }}
5 | button(href='#' v-on:click.stop='inc' style='display:inline-block; width:2em') +
6 | button(href='#' v-on:click.stop='dec' style='display:inline-block; width:2em') -
7 | button(href='#' v-on:click.stop='inverse=counter' style='display:inline-block; width:2em') !
8 | span(style='display:inline-block; width:3em; text-align: center') {{ inverse }}
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/test/test/__snapshots__/counter-js.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`counter-js.vue should just work 1`] = `
4 | "span(style='display: inline-block; width: 6em;') counter-js
5 | span(style='display: inline-block; width: 3em; text-align: center;') -3
6 | button(href='#', style='display: inline-block; width: 2em;') +
7 | button(href='#', style='display: inline-block; width: 2em;') -
8 | button(href='#', style='display: inline-block; width: 2em;') !
9 | span(style='display: inline-block; width: 3em; text-align: center;') 3
10 | "
11 | `;
12 |
--------------------------------------------------------------------------------
/test/test/__snapshots__/counter-ts.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`counter-ts.vue should just work 1`] = `
4 | "span(style='display: inline-block; width: 6em;') counter-ts
5 | span(style='display: inline-block; width: 3em; text-align: center;') -3
6 | button(href='#', style='display: inline-block; width: 2em;') +
7 | button(href='#', style='display: inline-block; width: 2em;') -
8 | button(href='#', style='display: inline-block; width: 2em;') !
9 | span(style='display: inline-block; width: 3em; text-align: center;') 3
10 | "
11 | `;
12 |
--------------------------------------------------------------------------------
/test/test/counter-js.spec.js:
--------------------------------------------------------------------------------
1 | const Vue = require('vue')
2 | const VJU = require('../../src/vue-jest-utils.ts')
3 |
4 | const CounterJs = require('../src/counter-js.vue')
5 |
6 | describe('counter-js.vue', () => {
7 | it('should just work', () => {
8 | const vm = new Vue({
9 | el: document.createElement('div'),
10 | render: (h) => h(CounterJs),
11 | })
12 | VJU.clickNthButton(vm.$el, 1)
13 | VJU.clickNthButton(vm.$el, 3)
14 | VJU.clickNthButton(vm.$el, 2)
15 | return VJU.expectToMatchSnapshot(vm)
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/test/test/counter-ts.spec.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import Vue = require('vue')
4 | import {expectToMatchSnapshot, clickNthButton} from '../../src/vue-jest-utils'
5 | import CounterTs = require('../src/counter-ts.vue')
6 |
7 | describe('counter-ts.vue', () => {
8 | it('should just work', () => {
9 | const vm = new Vue({
10 | el: document.createElement('div'),
11 | render: (h) => h(CounterTs),
12 | })
13 | clickNthButton(vm.$el, 1)
14 | clickNthButton(vm.$el, 3)
15 | clickNthButton(vm.$el, 2)
16 | return expectToMatchSnapshot(vm)
17 | })
18 | })
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "noImplicitAny": true,
6 | "strictNullChecks": true,
7 | "noUnusedLocals": true,
8 | "sourceMap": false,
9 | "pretty": true,
10 | "declaration": true,
11 | "lib": ["es5", "dom", "es2015.core", "es2015.promise"]
12 | },
13 | "exclude": [
14 | "node_modules",
15 | "lib"
16 | ],
17 | "atom": {
18 | "rewriteTsconfig": false
19 | },
20 | "compileOnSave": false
21 | }
22 |
--------------------------------------------------------------------------------
/tsconfigDist.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig",
3 | "compilerOptions": {
4 | "outDir": "lib"
5 | },
6 | "exclude": [
7 | "node_modules",
8 | "lib",
9 | "test"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint-config-locoslab"
3 | }
4 |
--------------------------------------------------------------------------------
/types/html2jade.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'html2jade' {
2 | function convertHtml(html: string, options?: Object, callback?: (err: any, jade: string) => void): void
3 | function convertDocument(html: string, options?: Object, callback?: (err: any, jade: string) => void): void
4 | }
5 |
--------------------------------------------------------------------------------