From 746c1063d2301b920cf69e63dca8b802f2f6e169 Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 16 Jun 2018 13:27:17 +0900 Subject: [PATCH 1/6] fix: set wrapper.vm if the element binds Vue instance --- .../test-utils/src/find-vue-components.js | 15 ++++++++++++- packages/test-utils/src/find.js | 21 +++++++++++++++++-- packages/test-utils/src/wrapper.js | 13 +++++++++++- test/specs/wrapper/find.spec.js | 18 ++++++++++++++++ test/specs/wrapper/findAll.spec.js | 18 ++++++++++++++++ test/specs/wrapper/setChecked.spec.js | 8 +++---- test/specs/wrapper/setSelected.spec.js | 8 +++---- test/specs/wrapper/setValue.spec.js | 11 +++++----- test/specs/wrapper/text.spec.js | 13 ++++++------ test/specs/wrapper/trigger.spec.js | 12 +++++------ 10 files changed, 105 insertions(+), 32 deletions(-) diff --git a/packages/test-utils/src/find-vue-components.js b/packages/test-utils/src/find-vue-components.js index 54c936d9a..e20e19744 100644 --- a/packages/test-utils/src/find-vue-components.js +++ b/packages/test-utils/src/find-vue-components.js @@ -90,7 +90,20 @@ export function vmFunctionalCtorMatchesSelector ( return Ctors.some(c => Ctor[c] === component[FUNCTIONAL_OPTIONS]._Ctor[c]) } -export default function findVueComponents ( +export function findVueComponentByElement ( + vm: Component, + elem: Element +): ?Component { + const components = findAllVueComponentsFromVm(vm) + for (let i = 0, max = components.length; i < max; i++) { + const component = components[i] + if (component.$el === elem) { + return component + } + } +} + +export function findVueComponents ( root: Component, selectorType: ?string, selector: Object diff --git a/packages/test-utils/src/find.js b/packages/test-utils/src/find.js index ef983d7f1..1308b2b3d 100644 --- a/packages/test-utils/src/find.js +++ b/packages/test-utils/src/find.js @@ -1,13 +1,28 @@ // @flow import findVnodes from './find-vnodes' -import findVueComponents from './find-vue-components' +import { + findVueComponents, + findVueComponentByElement +} from './find-vue-components' import findDOMNodes from './find-dom-nodes' import { COMPONENT_SELECTOR, NAME_SELECTOR, DOM_SELECTOR } from './consts' import Vue from 'vue' import getSelectorTypeOrThrow from './get-selector-type' import { throwError } from 'shared/util' +// Returns a component if the element binds a Vue instance. +function replaceBindingComponent (vnode: VNode): VNode | Component { + if (vnode.elm && vnode.elm.__vue__) { + const component = + findVueComponentByElement(vnode.elm.__vue__.$root, vnode.elm) + if (component) { + return component + } + } + return vnode +} + export default function find ( vm: Component | null, vnode: VNode | null, @@ -43,11 +58,13 @@ export default function find ( if (vnode) { const nodes = findVnodes(vnode, vm, selectorType, selector) + .map(replaceBindingComponent) if (selectorType !== DOM_SELECTOR) { return nodes } return nodes.length > 0 ? nodes : findDOMNodes(element, selector) + .map(replaceBindingComponent) } - return findDOMNodes(element, selector) + return findDOMNodes(element, selector).map(replaceBindingComponent) } diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index 81a9b2161..ae4d1641c 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -323,6 +323,11 @@ export default class Wrapper implements BaseWrapper { typeof selector === 'string' ? selector : 'Component' ) } + // Using CSS Selector, returns a VueWrapper instance if the root element + // binds a Vue instance. + if (nodes[0].$el === this.element && nodes[0].$parent === undefined) { + return this + } return createWrapper(nodes[0], this.options) } @@ -333,7 +338,13 @@ export default class Wrapper implements BaseWrapper { findAll (selector: Selector): WrapperArray { getSelectorTypeOrThrow(selector, 'findAll') const nodes = findAll(this.vm, this.vnode, this.element, selector) - const wrappers = nodes.map(node => createWrapper(node, this.options)) + const wrappers = nodes.map(node => { + // Using CSS Selector, returns a VueWrapper instance if the root element + // binds a Vue instance. + return node.$el === this.element && node.$parent === undefined + ? this + : createWrapper(node, this.options) + }) return new WrapperArray(wrappers) } diff --git a/test/specs/wrapper/find.spec.js b/test/specs/wrapper/find.spec.js index fb7677f66..ae2fb7e62 100644 --- a/test/specs/wrapper/find.spec.js +++ b/test/specs/wrapper/find.spec.js @@ -20,12 +20,14 @@ describeWithShallowAndMount('find', mountingMethod => { const compiled = compileToFunctions('

') const wrapper = mountingMethod(compiled) expect(wrapper.find('p').vnode).to.be.an('object') + expect(wrapper.find('p').vm).to.equal(undefined) }) it('returns Wrapper matching class selector passed', () => { const compiled = compileToFunctions('
') const wrapper = mountingMethod(compiled) expect(wrapper.find('.foo').vnode).to.be.an('object') + expect(wrapper.find('.foo').vm).to.equal(undefined) }) it('returns Wrapper matching class selector passed if nested in a transition', () => { @@ -395,4 +397,20 @@ describeWithShallowAndMount('find', mountingMethod => { .with.property('message', message) }) }) + + itDoNotRunIf( + mountingMethod.name === 'shallowMount', + 'returns a VueWrapper instance by CSS selector if the element binds a Vue instance', () => { + const childComponent = { + name: 'bar', + template: '

' + } + const wrapper = mountingMethod({ + name: 'foo', + template: '

', + components: { childComponent } + }) + expect(wrapper.find('div').vm.$options.name).to.equal('foo') + expect(wrapper.find('p').vm.$options.name).to.equal('bar') + }) }) diff --git a/test/specs/wrapper/findAll.spec.js b/test/specs/wrapper/findAll.spec.js index 7908fe6df..72e785a5f 100644 --- a/test/specs/wrapper/findAll.spec.js +++ b/test/specs/wrapper/findAll.spec.js @@ -323,4 +323,22 @@ describeWithShallowAndMount('findAll', mountingMethod => { .with.property('message', message) }) }) + + itDoNotRunIf( + mountingMethod.name === 'shallowMount', + 'returns a WrapperArray which includes VueWrapper if the elements binds a Vue instance', () => { + const childComponent = { + name: 'bar', + template: '

' + } + const wrapper = mountingMethod({ + name: 'foo', + template: '

', + components: { childComponent } + }) + const wrappers = wrapper.findAll('.foo') + expect(wrappers.at(0).vm.$options.name).to.equal('foo') + expect(wrappers.at(1).vm).to.equal(undefined) + expect(wrappers.at(2).vm.$options.name).to.equal('bar') + }) }) diff --git a/test/specs/wrapper/setChecked.spec.js b/test/specs/wrapper/setChecked.spec.js index 2cbd6da16..44e3423f7 100644 --- a/test/specs/wrapper/setChecked.spec.js +++ b/test/specs/wrapper/setChecked.spec.js @@ -84,11 +84,11 @@ describeWithShallowAndMount('setChecked', mountingMethod => { }) it('throws error if wrapper does not contain element', () => { - const wrapper = mountingMethod({ render: h => h('div') }) - const div = wrapper.find('div') - div.element = null + const wrapper = mountingMethod({ template: '

' }) + const p = wrapper.find('p') + p.element = null - const fn = () => div.setChecked() + const fn = () => p.setChecked() const message = '[vue-test-utils]: cannot call wrapper.setChecked() on a wrapper without an element' expect(fn) diff --git a/test/specs/wrapper/setSelected.spec.js b/test/specs/wrapper/setSelected.spec.js index f60b3ed26..474f32fc8 100644 --- a/test/specs/wrapper/setSelected.spec.js +++ b/test/specs/wrapper/setSelected.spec.js @@ -34,11 +34,11 @@ describeWithShallowAndMount('setSelected', mountingMethod => { }) it('throws error if wrapper does not contain element', () => { - const wrapper = mountingMethod({ render: h => h('div') }) - const div = wrapper.find('div') - div.element = null + const wrapper = mountingMethod({ template: '

' }) + const p = wrapper.find('p') + p.element = null - const fn = () => div.setSelected() + const fn = () => p.setSelected() const message = '[vue-test-utils]: cannot call wrapper.setSelected() on a wrapper without an element' expect(fn) diff --git a/test/specs/wrapper/setValue.spec.js b/test/specs/wrapper/setValue.spec.js index 228c658fc..0727a798a 100644 --- a/test/specs/wrapper/setValue.spec.js +++ b/test/specs/wrapper/setValue.spec.js @@ -20,12 +20,11 @@ describeWithShallowAndMount('setValue', mountingMethod => { }) it('throws error if wrapper does not contain element', () => { - const wrapper = mountingMethod({ render: h => h('div') }) - const div = wrapper.find('div') - div.element = null - const fn = () => div.setValue('') - const message = - '[vue-test-utils]: cannot call wrapper.setValue() on a wrapper without an element' + const wrapper = mountingMethod({ template: '

' }) + const p = wrapper.find('p') + p.element = null + const fn = () => p.setValue('') + const message = '[vue-test-utils]: cannot call wrapper.setValue() on a wrapper without an element' expect(fn) .to.throw() .with.property('message', message) diff --git a/test/specs/wrapper/text.spec.js b/test/specs/wrapper/text.spec.js index 72634eddb..7e45f013e 100644 --- a/test/specs/wrapper/text.spec.js +++ b/test/specs/wrapper/text.spec.js @@ -20,14 +20,13 @@ describeWithShallowAndMount('text', mountingMethod => { expect(wrapper.text()).to.equal(text) }) - 152 + it('throws error if wrapper does not contain element', () => { - const wrapper = mountingMethod({ render: h => h('div') }) - const div = wrapper.find('div') - div.element = null - const fn = () => div.text() - const message = - '[vue-test-utils]: cannot call wrapper.text() on a wrapper without an element' + const wrapper = mountingMethod({ template: '

' }) + const p = wrapper.find('p') + p.element = null + const fn = () => p.text() + const message = '[vue-test-utils]: cannot call wrapper.text() on a wrapper without an element' expect(fn) .to.throw() .with.property('message', message) diff --git a/test/specs/wrapper/trigger.spec.js b/test/specs/wrapper/trigger.spec.js index 9b102ad14..3adfbf749 100644 --- a/test/specs/wrapper/trigger.spec.js +++ b/test/specs/wrapper/trigger.spec.js @@ -158,15 +158,13 @@ describeWithShallowAndMount('trigger', mountingMethod => { }) it('throws error if wrapper does not contain element', () => { - const wrapper = mountingMethod({ render: h => h('div') }) - const div = wrapper.find('div') - div.element = null - const fn = () => div.trigger('click') + const wrapper = mountingMethod({ template: '

' }) + const p = wrapper.find('p') + p.element = null + const fn = () => p.trigger('click') const message = '[vue-test-utils]: cannot call wrapper.trigger() on a wrapper without an element' - expect(fn) - .to.throw() - .with.property('message', message) + expect(fn).to.throw().with.property('message', message) }) it('throws an error if type is not a string', () => { From ac07c713971b9ae8d04d730e7defd0b5303fa870 Mon Sep 17 00:00:00 2001 From: 38elements Date: Mon, 18 Jun 2018 01:24:40 +0900 Subject: [PATCH 2/6] check componentInstance --- packages/test-utils/src/create-wrapper.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/test-utils/src/create-wrapper.js b/packages/test-utils/src/create-wrapper.js index 23043460b..cf6fbd43e 100644 --- a/packages/test-utils/src/create-wrapper.js +++ b/packages/test-utils/src/create-wrapper.js @@ -7,7 +7,10 @@ import VueWrapper from './vue-wrapper' export default function createWrapper ( node: VNode | Component, options: WrapperOptions -) { +): VueWrapper | Wrapper { + if (node.componentInstance) { + return new VueWrapper(node.componentInstance, options) + } return node instanceof Vue ? new VueWrapper(node, options) : new Wrapper(node, options) From d9063eb727b6f06a70dc8769ff7add394e5b4095 Mon Sep 17 00:00:00 2001 From: 38elements Date: Mon, 18 Jun 2018 01:49:07 +0900 Subject: [PATCH 3/6] remove map(replaceBindingComponent) --- packages/test-utils/src/find.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/test-utils/src/find.js b/packages/test-utils/src/find.js index 1308b2b3d..e0dde5c4e 100644 --- a/packages/test-utils/src/find.js +++ b/packages/test-utils/src/find.js @@ -58,13 +58,11 @@ export default function find ( if (vnode) { const nodes = findVnodes(vnode, vm, selectorType, selector) - .map(replaceBindingComponent) if (selectorType !== DOM_SELECTOR) { return nodes } return nodes.length > 0 ? nodes : findDOMNodes(element, selector) - .map(replaceBindingComponent) } - return findDOMNodes(element, selector).map(replaceBindingComponent) + return findDOMNodes(element, selector) } From fc7b713ff9923fe21b64c44097c8bf94daf8bdb6 Mon Sep 17 00:00:00 2001 From: 38elements Date: Mon, 18 Jun 2018 01:58:56 +0900 Subject: [PATCH 4/6] add map(replaceBindingComponent) --- packages/test-utils/src/find.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/test-utils/src/find.js b/packages/test-utils/src/find.js index e0dde5c4e..2bdc1e3a6 100644 --- a/packages/test-utils/src/find.js +++ b/packages/test-utils/src/find.js @@ -58,11 +58,14 @@ export default function find ( if (vnode) { const nodes = findVnodes(vnode, vm, selectorType, selector) + .map(replaceBindingComponent) if (selectorType !== DOM_SELECTOR) { return nodes } return nodes.length > 0 ? nodes : findDOMNodes(element, selector) + .map(replaceBindingComponent) } return findDOMNodes(element, selector) + .map(replaceBindingComponent) } From 19c024379f6ab953e128a7c6ca321dc6808371fc Mon Sep 17 00:00:00 2001 From: 38elements Date: Mon, 18 Jun 2018 08:47:16 +0900 Subject: [PATCH 5/6] remove replaceBindingComponent() --- .../test-utils/src/find-vue-components.js | 15 +------------- packages/test-utils/src/find.js | 20 +------------------ packages/test-utils/src/wrapper.js | 4 ++-- test/specs/wrapper/trigger.spec.js | 4 +++- 4 files changed, 7 insertions(+), 36 deletions(-) diff --git a/packages/test-utils/src/find-vue-components.js b/packages/test-utils/src/find-vue-components.js index e20e19744..54c936d9a 100644 --- a/packages/test-utils/src/find-vue-components.js +++ b/packages/test-utils/src/find-vue-components.js @@ -90,20 +90,7 @@ export function vmFunctionalCtorMatchesSelector ( return Ctors.some(c => Ctor[c] === component[FUNCTIONAL_OPTIONS]._Ctor[c]) } -export function findVueComponentByElement ( - vm: Component, - elem: Element -): ?Component { - const components = findAllVueComponentsFromVm(vm) - for (let i = 0, max = components.length; i < max; i++) { - const component = components[i] - if (component.$el === elem) { - return component - } - } -} - -export function findVueComponents ( +export default function findVueComponents ( root: Component, selectorType: ?string, selector: Object diff --git a/packages/test-utils/src/find.js b/packages/test-utils/src/find.js index 2bdc1e3a6..ef983d7f1 100644 --- a/packages/test-utils/src/find.js +++ b/packages/test-utils/src/find.js @@ -1,28 +1,13 @@ // @flow import findVnodes from './find-vnodes' -import { - findVueComponents, - findVueComponentByElement -} from './find-vue-components' +import findVueComponents from './find-vue-components' import findDOMNodes from './find-dom-nodes' import { COMPONENT_SELECTOR, NAME_SELECTOR, DOM_SELECTOR } from './consts' import Vue from 'vue' import getSelectorTypeOrThrow from './get-selector-type' import { throwError } from 'shared/util' -// Returns a component if the element binds a Vue instance. -function replaceBindingComponent (vnode: VNode): VNode | Component { - if (vnode.elm && vnode.elm.__vue__) { - const component = - findVueComponentByElement(vnode.elm.__vue__.$root, vnode.elm) - if (component) { - return component - } - } - return vnode -} - export default function find ( vm: Component | null, vnode: VNode | null, @@ -58,14 +43,11 @@ export default function find ( if (vnode) { const nodes = findVnodes(vnode, vm, selectorType, selector) - .map(replaceBindingComponent) if (selectorType !== DOM_SELECTOR) { return nodes } return nodes.length > 0 ? nodes : findDOMNodes(element, selector) - .map(replaceBindingComponent) } return findDOMNodes(element, selector) - .map(replaceBindingComponent) } diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index ae4d1641c..d4eff61a2 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -325,7 +325,7 @@ export default class Wrapper implements BaseWrapper { } // Using CSS Selector, returns a VueWrapper instance if the root element // binds a Vue instance. - if (nodes[0].$el === this.element && nodes[0].$parent === undefined) { + if (nodes[0].elm === this.element) { return this } return createWrapper(nodes[0], this.options) @@ -341,7 +341,7 @@ export default class Wrapper implements BaseWrapper { const wrappers = nodes.map(node => { // Using CSS Selector, returns a VueWrapper instance if the root element // binds a Vue instance. - return node.$el === this.element && node.$parent === undefined + return node.elm === this.element ? this : createWrapper(node, this.options) }) diff --git a/test/specs/wrapper/trigger.spec.js b/test/specs/wrapper/trigger.spec.js index 3adfbf749..457df809b 100644 --- a/test/specs/wrapper/trigger.spec.js +++ b/test/specs/wrapper/trigger.spec.js @@ -164,7 +164,9 @@ describeWithShallowAndMount('trigger', mountingMethod => { const fn = () => p.trigger('click') const message = '[vue-test-utils]: cannot call wrapper.trigger() on a wrapper without an element' - expect(fn).to.throw().with.property('message', message) + expect(fn) + .to.throw() + .with.property('message', message) }) it('throws an error if type is not a string', () => { From 0e4d732ec2e557030a77f4ca61b638d738d5d6ed Mon Sep 17 00:00:00 2001 From: 38elements Date: Mon, 18 Jun 2018 22:28:40 +0900 Subject: [PATCH 6/6] fix createWrapper() --- packages/test-utils/src/create-wrapper.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/test-utils/src/create-wrapper.js b/packages/test-utils/src/create-wrapper.js index cf6fbd43e..dbd69d993 100644 --- a/packages/test-utils/src/create-wrapper.js +++ b/packages/test-utils/src/create-wrapper.js @@ -8,8 +8,9 @@ export default function createWrapper ( node: VNode | Component, options: WrapperOptions ): VueWrapper | Wrapper { - if (node.componentInstance) { - return new VueWrapper(node.componentInstance, options) + const componentInstance = node.componentInstance || node.child + if (componentInstance) { + return new VueWrapper(componentInstance, options) } return node instanceof Vue ? new VueWrapper(node, options)