Skip to content

Commit

Permalink
feat(test-utils): add 'overview' function (#1491)
Browse files Browse the repository at this point in the history
* feat(test-utils): add 'overview' function

close #1461

* feat(test-utils): add error wrapper overview

* fix(test-utils): fix flow errors

* fix(test-utils): compatibility with older versions

* fix(test utils): flow error

* feat: overview function PR comments

Co-authored-by: root <root@LAPTOP-VOQ3N65A.localdomain>
  • Loading branch information
SergiCL and root committed Apr 8, 2020
1 parent 9f93d5c commit 4b0c5c9
Show file tree
Hide file tree
Showing 8 changed files with 565 additions and 0 deletions.
43 changes: 43 additions & 0 deletions docs/api/wrapper/overview.md
@@ -0,0 +1,43 @@
## overview

Prints a simple overview of the `Wrapper`.

- **Example:**

```js
import { mount } from '@vue/test-utils'
import Component from './Component.vue'

const wrapper = mount(Component)
wrapper.overview()

// Console output
/*
Wrapper (Visible):
Html:
<div class="test">
<p>My name is Tess Ting</p>
</div>
Data: {
firstName: Tess,
lastName: Ting
}
Computed: {
fullName: Tess Ting'
}
Emitted: {',
foo: [',
0: [ hello, world ],
1: [ bye, world ]'
],
bar: [
0: [ hey ]'
]
}
*/
```
1 change: 1 addition & 0 deletions flow/wrapper.flow.js
Expand Up @@ -26,6 +26,7 @@ declare interface BaseWrapper {
isVisible(): boolean | void;
isVueInstance(): boolean | void;
name(): string | void;
overview(): void;
props(key?: string): { [name: string]: any } | any | void;
text(): string | void;
selector: Selector | void;
Expand Down
8 changes: 8 additions & 0 deletions packages/test-utils/src/error-wrapper.js
Expand Up @@ -187,6 +187,14 @@ export default class ErrorWrapper implements BaseWrapper {
)
}

overview(): void {
throwError(
`find did not return ${buildSelectorString(
this.selector
)}, cannot call overview() on empty Wrapper`
)
}

props(): void {
throwError(
`find did not return ${buildSelectorString(
Expand Down
9 changes: 9 additions & 0 deletions packages/test-utils/src/wrapper-array.js
Expand Up @@ -143,6 +143,15 @@ export default class WrapperArray implements BaseWrapper {
)
}

overview(): void {
this.throwErrorIfWrappersIsEmpty('overview()')

throwError(
`overview() must be called on a single wrapper, use at(i) ` +
`to access a wrapper`
)
}

props(): void {
this.throwErrorIfWrappersIsEmpty('props')

Expand Down
71 changes: 71 additions & 0 deletions packages/test-utils/src/wrapper.js
Expand Up @@ -324,6 +324,77 @@ export default class Wrapper implements BaseWrapper {
return this.vnode.tag
}

/**
* Prints a simple overview of the wrapper current state
* with useful information for debugging
*/
overview(): void {
if (!this.isVueInstance()) {
throwError(`wrapper.overview() can only be called on a Vue instance`)
}

const identation = 4
const formatJSON = (json: any, replacer: Function | null = null) =>
JSON.stringify(json, replacer, identation).replace(/"/g, '')

const visibility = this.isVisible() ? 'Visible' : 'Not visible'

const html = this.html()
? this.html().replace(/^(?!\s*$)/gm, ' '.repeat(identation)) + '\n'
: ''

// $FlowIgnore
const data = formatJSON(this.vm.$data)

/* eslint-disable operator-linebreak */
// $FlowIgnore
const computed = this.vm._computedWatchers
? formatJSON(
// $FlowIgnore
...Object.keys(this.vm._computedWatchers).map(computedKey => ({
// $FlowIgnore
[computedKey]: this.vm[computedKey]
}))
)
: // $FlowIgnore
this.vm.$options.computed
? formatJSON(
// $FlowIgnore
...Object.entries(this.vm.$options.computed).map(([key, value]) => ({
// $FlowIgnore
[key]: value()
}))
)
: '{}'
/* eslint-enable operator-linebreak */

const emittedJSONReplacer = (key, value) =>
value instanceof Array
? value.map((calledWith, index) => {
const callParams = calledWith.map(param =>
typeof param === 'object'
? JSON.stringify(param)
.replace(/"/g, '')
.replace(/,/g, ', ')
: param
)

return `${index}: [ ${callParams.join(', ')} ]`
})
: value

const emitted = formatJSON(this.emitted(), emittedJSONReplacer)

console.log(
'\n' +
`Wrapper (${visibility}):\n\n` +
`Html:\n${html}\n` +
`Data: ${data}\n\n` +
`Computed: ${computed}\n\n` +
`Emitted: ${emitted}\n`
)
}

/**
* Returns an Object containing the prop name/value pairs on the element
*/
Expand Down
1 change: 1 addition & 0 deletions test/specs/error-wrapper.spec.js
Expand Up @@ -22,6 +22,7 @@ describeWithShallowAndMount('ErrorWrapper', mountingMethod => {
'isVisible',
'isVueInstance',
'name',
'overview',
'props',
'setComputed',
'setMethods',
Expand Down
24 changes: 24 additions & 0 deletions test/specs/wrapper-array/overview.spec.js
@@ -0,0 +1,24 @@
import { describeWithShallowAndMount } from '~resources/utils'
import { compileToFunctions } from 'vue-template-compiler'
import '@vue/test-utils'

describeWithShallowAndMount('overview', mountingMethod => {
it('throws error if wrapper array contains no items', () => {
const wrapper = mountingMethod(compileToFunctions('<div />'))
const message = '[vue-test-utils]: overview() cannot be called on 0 items'

expect(() => wrapper.findAll('p').overview())
.to.throw()
.with.property('message', message)
})

it('throws error when called on a WrapperArray', () => {
const wrapper = mountingMethod(compileToFunctions('<div><div /></div>'))
const message =
'[vue-test-utils]: overview() must be called on a single wrapper, use at(i) to access a wrapper'

expect(() => wrapper.findAll('div').overview())
.to.throw()
.with.property('message', message)
})
})

0 comments on commit 4b0c5c9

Please sign in to comment.