Skip to content

Commit

Permalink
feat: Optionally hide deprecation errors (#1518)
Browse files Browse the repository at this point in the history
* feat: add config to show deprecation warnings

* test: fix failing deprecated test

* test: skip tests in old version of vue

Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
  • Loading branch information
dobromir-hristov and lmiller1990 committed Apr 27, 2020
1 parent c2de268 commit 7a0b7e0
Show file tree
Hide file tree
Showing 16 changed files with 168 additions and 64 deletions.
3 changes: 2 additions & 1 deletion flow/config.flow.js
Expand Up @@ -3,5 +3,6 @@ declare type Config = {
mocks?: Object,
methods?: { [name: string]: Function },
provide?: Object,
silent?: boolean
silent?: boolean,
showDeprecationWarnings?: boolean
}
4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -98,7 +98,9 @@
"cz-conventional-changelog": "^3.0.2",
"husky": "^3.1.0",
"lint-staged": "^9.5.0",
"prettier": "^1.16.0"
"prettier": "^1.16.0",
"rollup-plugin-delete": "^1.2.0",
"rollup-plugin-replace": "^2.2.0"
},
"config": {
"commitizen": {
Expand Down
4 changes: 2 additions & 2 deletions packages/create-instance/create-component-stubs.js
Expand Up @@ -7,7 +7,7 @@ import {
capitalize,
hyphenate,
keys,
warn
warnDeprecated
} from '../shared/util'
import {
componentNeedsCompiling,
Expand Down Expand Up @@ -159,7 +159,7 @@ export function createStubFromComponent(

// DEPRECATED: converts string stub to template stub.
function createStubFromString(templateString: string, name: string): Component {
warn('String stubs are deprecated and will be removed in future versions')
warnDeprecated('Using a string for stubs')

if (templateContainsComponent(templateString, name)) {
throwError('options.stub cannot contain a circular reference')
Expand Down
9 changes: 3 additions & 6 deletions packages/shared/merge-options.js
@@ -1,6 +1,6 @@
// @flow
import { normalizeStubs, normalizeProvide } from './normalize'
import { warn } from 'shared/util'
import { warnDeprecated } from 'shared/util'

function getOption(option, config?: Object): any {
if (option === false) {
Expand Down Expand Up @@ -34,11 +34,8 @@ export function mergeOptions(
const methods = (getOption(options.methods, config.methods): {
[key: string]: Function
})

if (config.methods && Object.keys(config.methods).length) {
warn(
`config.methods has been deprecated. It will be removed in a future release`
)
if (methods && Object.keys(methods).length) {
warnDeprecated('overwriting methods via the `methods` property')
}

const provide = (getOption(options.provide, config.provide): Object)
Expand Down
8 changes: 8 additions & 0 deletions packages/shared/util.js
@@ -1,6 +1,7 @@
// @flow
import Vue from 'vue'
import semver from 'semver'
import { config } from '@vue/test-utils'

export function throwError(msg: string): void {
throw new Error(`[vue-test-utils]: ${msg}`)
Expand Down Expand Up @@ -85,3 +86,10 @@ export function getCheckedEvent() {
// change is handler for version 2.0 - 2.1.8, and 2.5+
return 'change'
}

export function warnDeprecated(method: string, fallback: string = '') {
if (!config.showDeprecationWarnings) return
let msg = `${method} is deprecated and will removed in the next major version`
if (fallback) msg += ` ${fallback}`
warn(msg)
}
2 changes: 1 addition & 1 deletion packages/test-utils/package.json
Expand Up @@ -10,7 +10,7 @@
],
"scripts": {
"build": "node scripts/build.js",
"build:test": "cross-env NODE_ENV=test node scripts/build.js"
"build:test": "cross-env NODE_ENV=test SHOW_DEPRECATIONS=false node scripts/build.js"
},
"repository": {
"type": "git",
Expand Down
6 changes: 6 additions & 0 deletions packages/test-utils/scripts/build.js
Expand Up @@ -6,6 +6,8 @@ const nodeResolve = require('rollup-plugin-node-resolve')
const commonjs = require('rollup-plugin-commonjs')
const chalk = require('chalk')
const json = require('rollup-plugin-json')
const replace = require('rollup-plugin-replace')
const del = require('rollup-plugin-delete')

function success(text) {
console.log(chalk.green(`${text} ✔`))
Expand Down Expand Up @@ -57,6 +59,10 @@ rollupOptions.forEach(options => {
input: resolve('src/index.js'),
external: ['vue', 'vue-template-compiler'],
plugins: [
del({ targets: 'dist/*' }),
replace({
'process.env.SHOW_DEPRECATIONS': process.env.SHOW_DEPRECATIONS
}),
flow(),
json(),
buble({
Expand Down
6 changes: 5 additions & 1 deletion packages/test-utils/src/config.js
Expand Up @@ -6,5 +6,9 @@ export default {
mocks: {},
methods: {},
provide: {},
silent: true
silent: true,
showDeprecationWarnings:
typeof process.env.SHOW_DEPRECATIONS !== 'undefined'
? process.env.SHOW_DEPRECATIONS
: true
}
64 changes: 41 additions & 23 deletions packages/test-utils/src/wrapper.js
Expand Up @@ -12,7 +12,12 @@ import {
import config from './config'
import WrapperArray from './wrapper-array'
import ErrorWrapper from './error-wrapper'
import { throwError, getCheckedEvent, isPhantomJS, warn } from 'shared/util'
import {
throwError,
getCheckedEvent,
isPhantomJS,
warnDeprecated
} from 'shared/util'
import find from './find'
import createWrapper from './create-wrapper'
import { recursivelySetData } from './recursively-set-data'
Expand Down Expand Up @@ -122,8 +127,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` instead'
warnDeprecated(
'contains',
'Use `wrapper.find`, `wrapper.findComponent` or `wrapper.get` instead'
)
const selector = getSelector(rawSelector, 'contains')
const nodes = find(this.rootNode, this.vm, selector)
Expand Down Expand Up @@ -171,9 +177,7 @@ export default class Wrapper implements BaseWrapper {
* Returns an Array containing custom events emitted by the Wrapper vm
*/
emittedByOrder(): Array<{ name: string, args: Array<any> }> {
warn(
'emittedByOrder is deprecated and will be removed in a future release. Use `wrapper.emitted` instead'
)
warnDeprecated('emittedByOrder', 'Use `wrapper.emitted` instead')
if (!this._emittedByOrder && !this.vm) {
throwError(
`wrapper.emittedByOrder() can only be called on a Vue instance`
Expand Down Expand Up @@ -201,9 +205,6 @@ export default class Wrapper implements BaseWrapper {
* matches the provided selector.
*/
get(rawSelector: Selector): Wrapper {
warn(
'get is deprecated and will be removed in a future release. Use `find` or `findComponent` instead'
)
const found = this.find(rawSelector)
if (found instanceof ErrorWrapper) {
throw new Error(`Unable to find ${rawSelector} within: ${this.html()}`)
Expand All @@ -218,8 +219,9 @@ export default class Wrapper implements BaseWrapper {
find(rawSelector: Selector): Wrapper | ErrorWrapper {
const selector = getSelector(rawSelector, 'find')
if (selector.type !== DOM_SELECTOR) {
warn(
'finding components with `find` is deprecated and will be removed in a future release. Use `findComponent` instead'
warnDeprecated(
'finding components with `find`',
'Use `findComponent` instead'
)
}
const node = find(this.rootNode, this.vm, selector)[0]
Expand All @@ -240,8 +242,9 @@ export default class Wrapper implements BaseWrapper {
findAll(rawSelector: Selector): WrapperArray {
const selector = getSelector(rawSelector, 'findAll')
if (selector.type !== DOM_SELECTOR) {
warn(
'finding components with `findAll` is deprecated and will be removed in a future release. Use `findAllComponents` instead'
warnDeprecated(
'finding components with `findAll`',
'Use `findAllComponents` instead'
)
}
const nodes = find(this.rootNode, this.vm, selector)
Expand Down Expand Up @@ -316,9 +319,7 @@ 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`
)
warnDeprecated('is', 'Use element.tagName instead')
const selector = getSelector(rawSelector, 'is')

if (selector.type === REF_SELECTOR) {
Expand All @@ -332,9 +333,9 @@ 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`
warnDeprecated(
'isEmpty',
'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 === ''
Expand All @@ -360,8 +361,10 @@ 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`)
warnDeprecated(
'isEmpty',
`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 (
Expand All @@ -382,14 +385,16 @@ 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`)
warnDeprecated(`isVueInstance`)
return !!this.vm
}

/**
* Returns name of component, or tag name if node is not a Vue component
*/
name(): string {
warnDeprecated(`name`)

if (this.vm) {
return (
this.vm.$options.name ||
Expand All @@ -410,6 +415,8 @@ export default class Wrapper implements BaseWrapper {
* with useful information for debugging
*/
overview(): void {
warnDeprecated(`overview`)

if (!this.isVueInstance()) {
throwError(`wrapper.overview() can only be called on a Vue instance`)
}
Expand Down Expand Up @@ -511,6 +518,11 @@ export default class Wrapper implements BaseWrapper {
* Checks radio button or checkbox element
*/
setChecked(checked: boolean = true): void {
warnDeprecated(
`setChecked`,
'When you migrate to VTU 2, use setValue instead.'
)

if (typeof checked !== 'boolean') {
throwError('wrapper.setChecked() must be passed a boolean')
}
Expand Down Expand Up @@ -558,6 +570,11 @@ export default class Wrapper implements BaseWrapper {
* Selects <option></option> element
*/
setSelected(): void {
warnDeprecated(
`setSelected`,
'When you migrate to VTU 2, use setValue instead.'
)

const tagName = this.element.tagName

if (tagName === 'SELECT') {
Expand Down Expand Up @@ -610,7 +627,8 @@ 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`)
warnDeprecated(`setMethods`)

if (!this.isVueInstance()) {
throwError(`wrapper.setMethods() can only be called on a Vue instance`)
}
Expand Down
3 changes: 2 additions & 1 deletion packages/test-utils/types/index.d.ts
Expand Up @@ -150,7 +150,8 @@ interface VueTestUtilsConfigOptions {
mocks?: Record<string, any>
methods?: Record<string, Function>
provide?: Record<string, any>,
silent?: Boolean
silent?: Boolean,
showDeprecationWarnings?: boolean
}

export declare function createLocalVue (): typeof Vue
Expand Down
15 changes: 15 additions & 0 deletions test/specs/config.spec.js
Expand Up @@ -17,6 +17,7 @@ describeWithShallowAndMount('config', mountingMethod => {
afterEach(() => {
config.stubs = configStubsSave
config.silent = configSilentSave
config.methods = {}
sandbox.reset()
sandbox.restore()
})
Expand Down Expand Up @@ -99,4 +100,18 @@ describeWithShallowAndMount('config', mountingMethod => {
await wrapper.vm.$nextTick()
expect(wrapper.find('[data-testid="expanded"]').exists()).to.equal(false)
})

it('allows control deprecation warnings visibility', () => {
config.showDeprecationWarnings = true
const Component = {
name: 'Foo',
template: '<div>Foo</div>'
}
const wrapper = mountingMethod(Component)
wrapper.name()
expect(console.error).to.be.calledWith(sandbox.match('name is deprecated'))
config.showDeprecationWarnings = false
wrapper.name()
expect(console.error).to.have.callCount(1)
})
})
2 changes: 1 addition & 1 deletion test/specs/mounting-options/slots.spec.js
Expand Up @@ -343,7 +343,7 @@ describeWithShallowAndMount('options.slots', mountingMethod => {
.with.property('message', message)
})

it('throws error if passed a number for named slots', () => {
it('throws error if passed an array of numbers for named slots', () => {
const TestComponent = {
name: 'component-with-slots',
functional: true,
Expand Down
6 changes: 3 additions & 3 deletions test/specs/mounting-options/stubs.spec.js
Expand Up @@ -630,6 +630,7 @@ describeWithShallowAndMount('options.stub', mountingMethod => {
)

it('warns when passing a string', () => {
config.showDeprecationWarnings = true
const StringComponent = '<div></div>'
mountingMethod(ComponentWithChild, {
stubs: {
Expand All @@ -638,9 +639,8 @@ describeWithShallowAndMount('options.stub', mountingMethod => {
})

expect(console.error).calledWith(
sandbox.match(
'[vue-test-utils]: String stubs are deprecated and will be removed in future versions'
)
sandbox.match('[vue-test-utils]: Using a string for stubs is deprecated')
)
config.showDeprecationWarnings = false
})
})
29 changes: 17 additions & 12 deletions test/specs/wrapper/setMethods.spec.js
@@ -1,7 +1,8 @@
import { compileToFunctions } from 'vue-template-compiler'
import ComponentWithMethods from '~resources/components/component-with-methods.vue'
import ComponentWithEvents from '~resources/components/component-with-events.vue'
import { describeWithShallowAndMount } from '~resources/utils'
import { describeWithShallowAndMount, vueVersion } from '~resources/utils'
import { itDoNotRunIf } from 'conditional-specs'

describeWithShallowAndMount('setMethods', mountingMethod => {
it('sets component data and updates nested vm nodes when called on Vue instance', () => {
Expand All @@ -19,15 +20,19 @@ describeWithShallowAndMount('setMethods', mountingMethod => {
expect(() => p.setMethods({ ready: true })).throw(Error, message)
})

it('should replace methods when tied to an event', () => {
const wrapper = mountingMethod(ComponentWithEvents)
expect(wrapper.vm.isActive).to.be.false
wrapper.find('.toggle').trigger('click')
expect(wrapper.vm.isActive).to.be.true
// Replace the toggle function so that the data supposedly won't change
const toggleActive = () => {}
wrapper.setMethods({ toggleActive })
wrapper.find('.toggle').trigger('click')
expect(wrapper.vm.isActive).to.be.true
})
itDoNotRunIf(
vueVersion < 2.2,
'should replace methods when tied to an event',
() => {
const wrapper = mountingMethod(ComponentWithEvents)
expect(wrapper.vm.isActive).to.be.false
wrapper.find('.toggle').trigger('click')
expect(wrapper.vm.isActive).to.be.true
// Replace the toggle function so that the data supposedly won't change
const toggleActive = () => {}
wrapper.setMethods({ toggleActive })
wrapper.find('.toggle').trigger('click')
expect(wrapper.vm.isActive).to.be.true
}
)
})

0 comments on commit 7a0b7e0

Please sign in to comment.