From 191e94bc20b5649d6471e7f55a01f7e895c209d2 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Thu, 23 Apr 2020 22:06:55 +1000 Subject: [PATCH] chore: add deprecation messages --- packages/test-utils/src/find.js | 51 +++++++++++++--- packages/test-utils/src/get-selector.js | 19 +++++- packages/test-utils/src/mount.js | 6 ++ packages/test-utils/src/wrapper.js | 81 ++++++++++++++++++++++--- test/specs/wrapper/find.spec.js | 15 +++++ test/specs/wrapper/findAll.spec.js | 16 +++++ 6 files changed, 169 insertions(+), 19 deletions(-) diff --git a/packages/test-utils/src/find.js b/packages/test-utils/src/find.js index d769f6c76..c948a680e 100644 --- a/packages/test-utils/src/find.js +++ b/packages/test-utils/src/find.js @@ -7,7 +7,7 @@ import { COMPONENT_SELECTOR, VUE_VERSION } from 'shared/consts' -import { throwError } from 'shared/util' +import { throwError, warn } from 'shared/util' import { matches } from './matches' export function findAllInstances(rootVm: any) { @@ -50,11 +50,11 @@ function removeDuplicateNodes(vNodes: Array): Array { return vNodes.filter((vNode, index) => index === vNodeElms.indexOf(vNode.elm)) } -export default function find( +function checkInvalidFind( root: VNode | Element, vm?: Component, selector: Selector -): Array { +) { if (root instanceof Element && selector.type !== DOM_SELECTOR) { throwError( `cannot find a Vue instance on a DOM node. The node ` + @@ -74,10 +74,6 @@ export default function find( ) } - if (root instanceof Element) { - return findDOMNodes(root, selector.value) - } - if (!root && selector.type !== DOM_SELECTOR) { throwError( `cannot find a Vue instance on a DOM node. The node ` + @@ -89,6 +85,47 @@ export default function find( if (!vm && selector.type === REF_SELECTOR) { throwError(`$ref selectors can only be used on Vue component ` + `wrappers`) } +} + +export function findComponent( + root: VNode | Element, + vm?: Component, + selector: Selector +): Array { + if (vm && vm.$refs && selector.value.ref in vm.$refs) { + const refs = vm.$refs[selector.value.ref] + return Array.isArray(refs) ? refs : [refs] + } + + const nodes = findAllVNodes(root, selector) + const dedupedNodes = removeDuplicateNodes(nodes) + + if (nodes.length > 0 || selector.type !== DOM_SELECTOR) { + return dedupedNodes + } +} + +export function find( + root: VNode | Element, + vm?: Component, + selector: Selector, + callee?: string +): Array { + if ( + ['get', 'find', 'findAll'].includes(callee) && + [REF_SELECTOR, COMPONENT_SELECTOR].includes(selector.type) + ) { + warn( + 'finding a component via `find`, `findAll` and `get` has been deprecated and will be removed in a future release. `find` now only works on DOM nodes.' + + ' Use `findComponent`, `findAllComponents` or `getComponent` to query for a component instead.' + ) + } + + checkInvalidFind(root, vm, selector) + + if (root instanceof Element) { + return findDOMNodes(root, selector.value) + } if (vm && vm.$refs && selector.value.ref in vm.$refs) { const refs = vm.$refs[selector.value.ref] diff --git a/packages/test-utils/src/get-selector.js b/packages/test-utils/src/get-selector.js index 6941ea002..810883c10 100644 --- a/packages/test-utils/src/get-selector.js +++ b/packages/test-utils/src/get-selector.js @@ -24,15 +24,28 @@ export function getSelectorType(selector: Selector): string { return INVALID_SELECTOR } -export default function getSelector( +export function getComponentSelector( selector: Selector, methodName: string ): Object { + const type = getSelectorType(selector) + if (type === DOM_SELECTOR) { + throwError( + `wrapper.${methodName}() must be passed a Vue constructor or valid find option object` + ) + } + + return { + type, + value: selector + } +} + +export function getSelector(selector: Selector, methodName: string): Object { const type = getSelectorType(selector) if (type === INVALID_SELECTOR) { throwError( - `wrapper.${methodName}() must be passed a valid CSS selector, Vue ` + - `constructor, or valid find option object` + `wrapper.${methodName}() must be passed a valid CSS selector, Vue constructor, or valid find option object` ) } return { diff --git a/packages/test-utils/src/mount.js b/packages/test-utils/src/mount.js index 0a0ef4128..b76be2f96 100644 --- a/packages/test-utils/src/mount.js +++ b/packages/test-utils/src/mount.js @@ -6,6 +6,7 @@ import { mergeOptions } from 'shared/merge-options' import config from './config' import warnIfNoWindow from './warn-if-no-window' import polyfill from './polyfill' +import { warn } from 'shared/util' import createWrapper from './create-wrapper' import createLocalVue from './create-local-vue' import { validateOptions } from 'shared/validate-options' @@ -22,6 +23,11 @@ export default function mount(component, options = {}) { const _Vue = createLocalVue(options.localVue) + if (Object.keys(config.methods).length) { + warn( + `config.methods has been deprecated. It will be removed in a future release` + ) + } const mergedOptions = mergeOptions(options, config) validateOptions(mergedOptions, component) diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index 1b21b6cf7..2ade730bc 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -2,13 +2,13 @@ import Vue from 'vue' import pretty from 'pretty' -import getSelector from './get-selector' +import { getComponentSelector, getSelector } from './get-selector' import { REF_SELECTOR, FUNCTIONAL_OPTIONS, VUE_VERSION } from 'shared/consts' import config from './config' import WrapperArray from './wrapper-array' import ErrorWrapper from './error-wrapper' -import { throwError, getCheckedEvent, isPhantomJS } from 'shared/util' -import find from './find' +import { throwError, getCheckedEvent, isPhantomJS, warn } from 'shared/util' +import { find, findComponent } from './find' import createWrapper from './create-wrapper' import { recursivelySetData } from './recursively-set-data' import { matches } from './matches' @@ -117,6 +117,9 @@ export default class Wrapper implements BaseWrapper { * Checks if wrapper contains provided selector. */ contains(rawSelector: Selector): boolean { + warn( + 'contains is deprecated and will be removed in a future release. Use `wrapper.find`, `wrapper.findComponent` or `wrapper.get`' + ) const selector = getSelector(rawSelector, 'contains') const nodes = find(this.rootNode, this.vm, selector) return nodes.length > 0 @@ -163,6 +166,9 @@ export default class Wrapper implements BaseWrapper { * Returns an Array containing custom events emitted by the Wrapper vm */ emittedByOrder(): Array<{ name: string, args: Array }> { + warn( + 'emittedByOrder is deprecated and will be removed in a future release. Use `wrapper.emitted` instead' + ) if (!this._emittedByOrder && !this.vm) { throwError( `wrapper.emittedByOrder() can only be called on a Vue instance` @@ -190,7 +196,7 @@ export default class Wrapper implements BaseWrapper { * matches the provided selector. */ get(rawSelector: Selector): Wrapper { - const found = this.find(rawSelector) + const found = this.find(rawSelector, 'get') if (found instanceof ErrorWrapper) { throw new Error(`Unable to find ${rawSelector} within: ${this.html()}`) } @@ -198,12 +204,34 @@ export default class Wrapper implements BaseWrapper { } /** - * Finds first node in tree of the current wrapper that + * Finds first component in tree of the current wrapper that + * matches the provided selector. + */ + findComponent(rawSelector: Selector): Wrapper | ErrorWrapper { + const selector = getComponentSelector(rawSelector, 'findComponent') + const node = findComponent( + this.rootNode, + this.vm, + selector, + 'findComponent' + )[0] + + if (!node) { + return new ErrorWrapper(rawSelector) + } + + const wrapper = createWrapper(node, this.options) + wrapper.selector = rawSelector + return wrapper + } + + /** + * Finds first DOM node in tree of the current wrapper that * matches the provided selector. */ - find(rawSelector: Selector): Wrapper | ErrorWrapper { + find(rawSelector: Selector, callee: string): Wrapper | ErrorWrapper { const selector = getSelector(rawSelector, 'find') - const node = find(this.rootNode, this.vm, selector)[0] + const node = find(this.rootNode, this.vm, selector, callee || 'find')[0] if (!node) { return new ErrorWrapper(rawSelector) @@ -215,12 +243,32 @@ export default class Wrapper implements BaseWrapper { } /** - * Finds node in tree of the current wrapper that matches + * Finds DOM nodes in tree of the current wrapper that matches * the provided selector. */ findAll(rawSelector: Selector): WrapperArray { const selector = getSelector(rawSelector, 'findAll') - const nodes = find(this.rootNode, this.vm, selector) + const nodes = find(this.rootNode, this.vm, selector, 'findAll') + const wrappers = nodes.map(node => { + // Using CSS Selector, returns a VueWrapper instance if the root element + // binds a Vue instance. + const wrapper = createWrapper(node, this.options) + wrapper.selector = rawSelector + return wrapper + }) + + const wrapperArray = new WrapperArray(wrappers) + wrapperArray.selector = rawSelector + return wrapperArray + } + + /** + * Finds components in tree of the current wrapper that matches + * the provided selector. + */ + findAllComponents(rawSelector: Selector): WrapperArray { + const selector = getComponentSelector(rawSelector, 'findAllComponents') + const nodes = find(this.rootNode, this.vm, selector, 'findAllComponents') const wrappers = nodes.map(node => { // Using CSS Selector, returns a VueWrapper instance if the root element // binds a Vue instance. @@ -245,6 +293,9 @@ export default class Wrapper implements BaseWrapper { * Checks if node matches selector */ is(rawSelector: Selector): boolean { + warn( + `is is deprecated and will be removed in a future release. Use element.tagName instead` + ) const selector = getSelector(rawSelector, 'is') if (selector.type === REF_SELECTOR) { @@ -258,6 +309,8 @@ export default class Wrapper implements BaseWrapper { * Checks if node is empty */ isEmpty(): boolean { + warn(`isEmpty is deprecated and will be removed in a future release. + Consider a custom matcher such as those provided in jest-dom: https://github.com/testing-library/jest-dom#tobeempty`) if (!this.vnode) { return this.element.innerHTML === '' } @@ -282,6 +335,8 @@ export default class Wrapper implements BaseWrapper { * Checks if node is visible */ isVisible(): boolean { + warn(`isEmpty is deprecated and will be removed in a future release. + Consider a custom matcher such as those provided in jest-dom: https://github.com/testing-library/jest-dom#tobevisible`) let element = this.element while (element) { if ( @@ -302,6 +357,7 @@ export default class Wrapper implements BaseWrapper { * Checks if wrapper is a vue instance */ isVueInstance(): boolean { + warn(`isVueInstance is deprecated and will be removed in a future release`) return !!this.vm } @@ -430,6 +486,9 @@ export default class Wrapper implements BaseWrapper { * Checks radio button or checkbox element */ setChecked(checked: boolean = true): void { + warn( + `setChecked has been renamed setValue. setChecked will be removed in a future release.` + ) if (typeof checked !== 'boolean') { throwError('wrapper.setChecked() must be passed a boolean') } @@ -477,6 +536,9 @@ export default class Wrapper implements BaseWrapper { * Selects element */ setSelected(): void { + warn( + `setSelected has been renamed setValue. setSelected will be removed in a future release.` + ) const tagName = this.element.tagName if (tagName === 'SELECT') { @@ -529,6 +591,7 @@ export default class Wrapper implements BaseWrapper { * Sets vm methods */ setMethods(methods: Object): void { + warn(`setMethods is deprecated and will be removed in a future release`) if (!this.isVueInstance()) { throwError(`wrapper.setMethods() can only be called on a Vue instance`) } diff --git a/test/specs/wrapper/find.spec.js b/test/specs/wrapper/find.spec.js index d457d0e32..46e3c5b9c 100644 --- a/test/specs/wrapper/find.spec.js +++ b/test/specs/wrapper/find.spec.js @@ -137,6 +137,21 @@ describeWithShallowAndMount('find', mountingMethod => { expect(wrapper.find(Component).vnode).to.be.an('object') }) + it('returns Wrapper of Vue Components matching component using findComponent', () => { + const wrapper = mountingMethod(ComponentWithChild) + expect(wrapper.findComponent(Component).vnode).to.be.an('object') + }) + + it('throws an error if findComponent selector is a CSS selector', () => { + const wrapper = mountingMethod(Component) + const message = + '[vue-test-utils]: wrapper.findComponent() must be passed a Vue constructor or valid find option object' + const fn = () => wrapper.findComponent('#foo') + expect(fn) + .to.throw() + .with.property('message', message) + }) + itSkipIf(isRunningPhantomJS, 'returns Wrapper of class component', () => { const TestComponent = { template: ` diff --git a/test/specs/wrapper/findAll.spec.js b/test/specs/wrapper/findAll.spec.js index c0ac72a5f..de17ce741 100644 --- a/test/specs/wrapper/findAll.spec.js +++ b/test/specs/wrapper/findAll.spec.js @@ -145,6 +145,22 @@ describeWithShallowAndMount('findAll', mountingMethod => { expect(componentArr.length).to.equal(1) }) + it('returns an array of VueWrappers of Vue Components matching componentusing findAllComponents', () => { + const wrapper = mountingMethod(ComponentWithChild) + const componentArr = wrapper.findAllComponents(Component) + expect(componentArr.length).to.equal(1) + }) + + it('throws an error if findComponent selector is a CSS selector', () => { + const wrapper = mountingMethod(Component) + const message = + '[vue-test-utils]: wrapper.findAllComponents() must be passed a Vue constructor or valid find option object' + const fn = () => wrapper.findAllComponents('#foo') + expect(fn) + .to.throw() + .with.property('message', message) + }) + it('returns correct number of Vue Wrapper when component has a v-for', () => { const items = [{ id: 1 }, { id: 2 }, { id: 3 }] const wrapper = mountingMethod(ComponentWithVFor, { propsData: { items } })