/
utils.js
172 lines (145 loc) · 4.21 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import { readFileSync } from 'fs'
import { resolve } from 'path'
import BootstrapVue from '../src'
const VUE_VERSION = process.env.VUE_VERSION ? 'vue-' + process.env.VUE_VERSION : 'vue'
const Vue = require(`${VUE_VERSION}/dist/vue.common`)
// Hide development mode warning
Vue.config.productionTip = false
// Install Vue and BootstrapVue
window.Vue = Vue
Vue.use(BootstrapVue)
export function loadFixture (dirName, name) {
const fixtureBase = resolve(dirName, 'fixtures')
const template = readFileSync(resolve(fixtureBase, name + '.html'), 'UTF-8')
const js = readFileSync(resolve(fixtureBase, name + '.js'), 'UTF-8')
return async () => {
// Mount template
document.body.innerHTML = template
// Eval js
// eslint-disable-next-line no-eval
eval(js)
// Await for Vue render
await Vue.nextTick()
}
}
export async function testVM () {
it(`vm mounts`, async () => {
return expect(window.app.$el).toBeDefined()
})
}
export function nextTick () {
return new Promise((resolve, reject) => {
Vue.nextTick(resolve)
})
}
export async function setData (app, key, value) {
app[key] = value
await nextTick()
}
// Usage: await sleep(1000);
export function sleep (ms) {
ms = ms || 0
return new Promise((resolve, reject) => setTimeout(resolve, ms))
}
const isVueInstance = vm => vm instanceof Vue
const isHTMLElement = el => el instanceof HTMLElement
const throwIfNotVueInstance = vm => {
if (!isVueInstance(vm)) {
// debugging breadcrumbs in case a non-Vue instance gets erroneously passed
// makes the error easier to fix than example: "Cannot read _prevClass of undefined"
console.error(vm)
throw new TypeError(
`The matcher function expects Vue instance. Given ${typeof vm}`
)
}
}
const throwIfNotHTMLElement = el => {
if (!isHTMLElement(el)) {
console.error(el)
throw new TypeError(
`The matcher function expects an HTML Element. Given ${typeof el}`
)
}
}
const throwIfNotArray = array => {
if (!Array.isArray(array)) {
throw new TypeError(`The matcher requires an array. Given ${typeof array}`)
}
}
const vmHasClass = (vm, className) => {
throwIfNotVueInstance(vm)
return vm.$el._prevClass.indexOf(className) !== -1
}
/**
* @param {HTMLElement} el
* @param {string} className
* @return {boolean}
*/
const elHasClass = (el, className) => {
throwIfNotHTMLElement(el)
return el.classList.contains(className)
}
/**
* @param {Vue|HTMLElement} node
* @param {string} className
* @return {boolean}
*/
const hasClass = (node, className) =>
isVueInstance(node)
? vmHasClass(node, className)
: elHasClass(node, className)
const getVmTag = vm => vm.$options._componentTag
const getHTMLTag = el => String(el.tagName).toLowerCase()
const getTagName = node =>
isVueInstance(node) ? getVmTag(node) : getHTMLTag(node)
// Extend Jest marchers
expect.extend({
toHaveClass (node, className) {
return {
message: () =>
`expected <${getTagName(node)}> to have class '${className}'`,
pass: hasClass(node, className)
}
},
toHaveAllClasses (node, classList) {
throwIfNotArray(classList)
let pass = true
let missingClassNames = []
classList.forEach(className => {
if (!hasClass(node, className)) {
pass = false
missingClassNames.push(className)
}
})
const plural = missingClassNames.length > 1
const classStr = classList.join(', ')
const missingClassStr = missingClassNames.join(', ')
const tagName = getTagName(node)
return {
// more debugging breadcrumbs
message: () =>
`Expected <${tagName}> to have all classes in [${classStr}], but was missing [${missingClassStr}] class${
plural ? 'es' : ''
}.`,
pass
}
},
toBeComponent (vm, componentTag) {
throwIfNotVueInstance(vm)
return {
message: () =>
`Expected to be <${componentTag}>. Received: ${getVmTag(vm)}`,
pass: getVmTag(vm) === componentTag
}
},
toBeElement (el, tagName) {
throwIfNotHTMLElement(el)
return {
message: () =>
`Expected to be <${String(
tagName
).toLowerCase()}>. Received: ${el.tagName.toLowerCase()}`,
pass: el.tagName === String(tagName).toUpperCase()
}
}
})