From 5950f50a96f75372ed2e57d29eda00aa5f34cadc Mon Sep 17 00:00:00 2001 From: 38elements Date: Sat, 23 Jun 2018 20:04:25 +0900 Subject: [PATCH 1/3] feat: change WrapperArray.wrappers and WrapperArray.length to read-only --- docs/api/wrapper-array/README.md | 8 ++++---- docs/api/wrapper/README.md | 4 ++-- packages/test-utils/src/wrapper-array.js | 17 +++++++++++++---- packages/test-utils/src/wrapper.js | 2 +- test/specs/wrapper-array.spec.js | 12 +++--------- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/docs/api/wrapper-array/README.md b/docs/api/wrapper-array/README.md index 9ad5dbde0..fa6c745cf 100644 --- a/docs/api/wrapper-array/README.md +++ b/docs/api/wrapper-array/README.md @@ -4,13 +4,13 @@ A `WrapperArray` is an object that contains an array of [`Wrappers`](../wrapper/ ## Properties -### `wrappers` +### `wrappers` -`array`: the `Wrappers` contained in the `WrapperArray` +`array` (read-only): the `Wrappers` contained in the `WrapperArray` -### `length` +### `length` -`number`: the number of `Wrappers` contained in the `WrapperArray` +`number` (read-only): the number of `Wrappers` contained in the `WrapperArray` ## Methods diff --git a/docs/api/wrapper/README.md b/docs/api/wrapper/README.md index b4765b6f4..7f4c5f012 100644 --- a/docs/api/wrapper/README.md +++ b/docs/api/wrapper/README.md @@ -14,13 +14,13 @@ A `Wrapper` is an object that contains a mounted component or vnode and methods `HTMLElement` (read-only): the root DOM node of the wrapper -### `options` +### `options` #### `options.attachedToDocument` `Boolean` (read-only): True if `attachedToDocument` in mounting options was `true` -#### `options.sync` +#### `options.sync` `Boolean` (read-only): True if `sync` in mounting options was not `false` diff --git a/packages/test-utils/src/wrapper-array.js b/packages/test-utils/src/wrapper-array.js index 4bf9d2ccf..3ee8548aa 100644 --- a/packages/test-utils/src/wrapper-array.js +++ b/packages/test-utils/src/wrapper-array.js @@ -5,12 +5,21 @@ import type VueWrapper from './vue-wrapper' import { throwError, warn } from 'shared/util' export default class WrapperArray implements BaseWrapper { - wrappers: Array; - length: number; + +wrappers: Array; + +length: number; constructor (wrappers: Array) { - this.wrappers = wrappers || [] - this.length = this.wrappers.length + const length = wrappers.length + // $FlowIgnore + Object.defineProperty(this, 'wrappers', { + get: () => wrappers, + set: () => {} + }) + // $FlowIgnore + Object.defineProperty(this, 'length', { + get: () => length, + set: () => {} + }) } at (index: number): Wrapper | VueWrapper { diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index a69fd7ff9..a589e9a9a 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -814,7 +814,7 @@ export default class Wrapper implements BaseWrapper { */ destroy () { if (!this.isVueInstance()) { - throwError(`wrapper.destroy() can only be called on a Vue ` + `instance`) + throwError(`wrapper.destroy() can only be called on a Vue instance`) } if (this.element.parentNode) { diff --git a/test/specs/wrapper-array.spec.js b/test/specs/wrapper-array.spec.js index dbd0217e2..f5276f023 100644 --- a/test/specs/wrapper-array.spec.js +++ b/test/specs/wrapper-array.spec.js @@ -7,11 +7,7 @@ describeWithShallowAndMount('WrapperArray', mountingMethod => { const wrapper = mountingMethod(compiled) const wrapperArray = wrapper.findAll('p') expect(wrapperArray.constructor.name).to.equal('WrapperArray') - if (wrappers) { - wrapperArray.wrappers = wrappers - wrapperArray.length = wrappers.length - } - return wrapperArray + return wrappers ? new wrapperArray.constructor(wrappers) : wrapperArray } it('returns class with length equal to length of wrappers passed in constructor', () => { @@ -67,8 +63,7 @@ describeWithShallowAndMount('WrapperArray', mountingMethod => { if (method === 'at') { return } - const wrapperArray = getWrapperArray() - wrapperArray.wrappers = [] + const wrapperArray = getWrapperArray([]) const message = `[vue-test-utils]: ${method} cannot be called on 0 items` expect(() => wrapperArray[method]()) .to.throw() @@ -99,8 +94,7 @@ describeWithShallowAndMount('WrapperArray', mountingMethod => { ) { return } - const wrapperArray = getWrapperArray() - wrapperArray.wrappers = [1, 2, 3] + const wrapperArray = getWrapperArray([1, 2, 3]) const message = `[vue-test-utils]: ${method} must be called on a single wrapper, use at(i) to access a wrapper` expect(() => wrapperArray[method]()) .to.throw() From 974be4ffcfb5c3ff88f4975ce278db9fa1d9a406 Mon Sep 17 00:00:00 2001 From: 38elements Date: Sun, 24 Jun 2018 01:00:58 +0900 Subject: [PATCH 2/3] throw error --- packages/test-utils/src/vue-wrapper.js | 7 ++++--- packages/test-utils/src/wrapper-array.js | 4 ++-- packages/test-utils/src/wrapper.js | 15 ++++++++------- test/specs/{vuewrapper.js => vue-wrapper.spec.js} | 7 ++++--- test/specs/wrapper-array.spec.js | 10 ++++++++++ test/specs/wrapper.spec.js | 7 ++++--- test/specs/wrapper/attributes.spec.js | 7 ------- test/specs/wrapper/is.spec.js | 6 ------ 8 files changed, 32 insertions(+), 31 deletions(-) rename test/specs/{vuewrapper.js => vue-wrapper.spec.js} (67%) diff --git a/packages/test-utils/src/vue-wrapper.js b/packages/test-utils/src/vue-wrapper.js index 289790a6b..bd94a0c33 100644 --- a/packages/test-utils/src/vue-wrapper.js +++ b/packages/test-utils/src/vue-wrapper.js @@ -1,6 +1,7 @@ // @flow import Wrapper from './wrapper' +import { throwError } from 'shared/util' import { setWatchersToSync } from './set-watchers-to-sync' import { orderWatchers } from './order-watchers' @@ -11,17 +12,17 @@ export default class VueWrapper extends Wrapper implements BaseWrapper { // $FlowIgnore : issue with defineProperty Object.defineProperty(this, 'vnode', { get: () => vm._vnode, - set: () => {} + set: () => throwError(`VueWrapper.vnode is read-only`) }) // $FlowIgnore Object.defineProperty(this, 'element', { get: () => vm.$el, - set: () => {} + set: () => throwError(`VueWrapper.element is read-only`) }) // $FlowIgnore Object.defineProperty(this, 'vm', { get: () => vm, - set: () => {} + set: () => throwError(`VueWrapper.vm is read-only`) }) if (options.sync) { setWatchersToSync(vm) diff --git a/packages/test-utils/src/wrapper-array.js b/packages/test-utils/src/wrapper-array.js index 3ee8548aa..d69c761da 100644 --- a/packages/test-utils/src/wrapper-array.js +++ b/packages/test-utils/src/wrapper-array.js @@ -13,12 +13,12 @@ export default class WrapperArray implements BaseWrapper { // $FlowIgnore Object.defineProperty(this, 'wrappers', { get: () => wrappers, - set: () => {} + set: () => throwError(`WrapperArray.wrappers is read-only`) }) // $FlowIgnore Object.defineProperty(this, 'length', { get: () => length, - set: () => {} + set: () => throwError(`WrapperArray.length is read-only`) }) } diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index a589e9a9a..f9decf705 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -24,6 +24,7 @@ import { orderWatchers } from './order-watchers' export default class Wrapper implements BaseWrapper { +vnode: VNode | null; + _vnode: VNode | null; +vm: Component | null; _emitted: { [name: string]: Array> }; _emittedByOrder: Array<{ name: string, args: Array }>; @@ -39,27 +40,28 @@ export default class Wrapper implements BaseWrapper { const element = node instanceof Element ? node : node.elm // Prevent redefine by VueWrapper if (this.constructor.name === 'Wrapper') { + this._vnode = vnode // $FlowIgnore Object.defineProperty(this, 'vnode', { - get: () => vnode, - set: () => {} + get: () => this._vnode, + set: () => throwError(`Wrapper.vnode is read-only`) }) // $FlowIgnore Object.defineProperty(this, 'element', { get: () => element, - set: () => {} + set: () => throwError(`Wrapper.element is read-only`) }) // $FlowIgnore Object.defineProperty(this, 'vm', { get: () => undefined, - set: () => {} + set: () => throwError(`Wrapper.vm is read-only`) }) } const frozenOptions = Object.freeze(options) // $FlowIgnore Object.defineProperty(this, 'options', { get: () => frozenOptions, - set: () => {} + set: () => throwError(`${this.constructor.name}.options is read-only`) }) if ( this.vnode && @@ -399,7 +401,6 @@ export default class Wrapper implements BaseWrapper { } return !!( - this.element && this.element.getAttribute && this.element.matches(selector) ) @@ -667,7 +668,7 @@ export default class Wrapper implements BaseWrapper { }) // $FlowIgnore : Problem with possibly null this.vm - this.vnode = this.vm._vnode + this._vnode = this.vm._vnode orderWatchers(this.vm || this.vnode.context.$root) Vue.config.silent = originalConfig } diff --git a/test/specs/vuewrapper.js b/test/specs/vue-wrapper.spec.js similarity index 67% rename from test/specs/vuewrapper.js rename to test/specs/vue-wrapper.spec.js index b909d9e31..dd847e2f5 100644 --- a/test/specs/vuewrapper.js +++ b/test/specs/vue-wrapper.spec.js @@ -5,9 +5,10 @@ describeWithShallowAndMount('VueWrapper', mountingMethod => { it(`has the ${property} property which is read-only`, () => { const wrapper = mountingMethod({ template: '

' }) expect(wrapper.constructor.name).to.equal('VueWrapper') - const originalProperty = wrapper[property] - wrapper[property] = 'foo' - expect(wrapper[property]).to.equal(originalProperty) + const message = `[vue-test-utils]: VueWrapper.${property} is read-only` + expect(() => { wrapper[property] = 'foo' }) + .to.throw() + .with.property('message', message) }) }) }) diff --git a/test/specs/wrapper-array.spec.js b/test/specs/wrapper-array.spec.js index f5276f023..2376d92b8 100644 --- a/test/specs/wrapper-array.spec.js +++ b/test/specs/wrapper-array.spec.js @@ -10,6 +10,16 @@ describeWithShallowAndMount('WrapperArray', mountingMethod => { return wrappers ? new wrapperArray.constructor(wrappers) : wrapperArray } + ['wrappers', 'length'].forEach(property => { + it(`has the ${property} property which is read-only`, () => { + const wrapperArray = getWrapperArray() + const message = `[vue-test-utils]: WrapperArray.${property} is read-only` + expect(() => { wrapperArray[property] = 'foo' }) + .to.throw() + .with.property('message', message) + }) + }) + it('returns class with length equal to length of wrappers passed in constructor', () => { const wrapperArray = getWrapperArray() expect(wrapperArray.length).to.equal(3) diff --git a/test/specs/wrapper.spec.js b/test/specs/wrapper.spec.js index 38fec40f0..41c82a55b 100644 --- a/test/specs/wrapper.spec.js +++ b/test/specs/wrapper.spec.js @@ -6,9 +6,10 @@ describeWithShallowAndMount('Wrapper', mountingMethod => { const wrapper = mountingMethod({ template: '

' }) .find('p') expect(wrapper.constructor.name).to.equal('Wrapper') - const originalProperty = wrapper[property] - wrapper[property] = 'foo' - expect(wrapper[property]).to.equal(originalProperty) + const message = `[vue-test-utils]: Wrapper.${property} is read-only` + expect(() => { wrapper[property] = 'foo' }) + .to.throw() + .with.property('message', message) }) }) }) diff --git a/test/specs/wrapper/attributes.spec.js b/test/specs/wrapper/attributes.spec.js index e93b91bfb..45af0851d 100644 --- a/test/specs/wrapper/attributes.spec.js +++ b/test/specs/wrapper/attributes.spec.js @@ -15,11 +15,4 @@ describeWithShallowAndMount('attributes', mountingMethod => { const wrapper = mountingMethod(compiled) expect(wrapper.attributes()).to.eql({}) }) - - it('returns empty object if wrapper element is null', () => { - const compiled = compileToFunctions('
') - const wrapper = mountingMethod(compiled) - wrapper.element = null - expect(wrapper.attributes()).to.eql({}) - }) }) diff --git a/test/specs/wrapper/is.spec.js b/test/specs/wrapper/is.spec.js index ca1cc83bd..606b2f32b 100644 --- a/test/specs/wrapper/is.spec.js +++ b/test/specs/wrapper/is.spec.js @@ -28,12 +28,6 @@ describeWithShallowAndMount('is', mountingMethod => { expect(wrapper.is('#div')).to.equal(true) }) - it('returns false if wrapper does not contain element', () => { - const wrapper = mountingMethod(ComponentWithChild) - wrapper.element = null - expect(wrapper.is('a')).to.equal(false) - }) - it('returns true if root node matches Vue Component selector', () => { const wrapper = mountingMethod(ComponentWithChild) const component = wrapper.findAll(Component).at(0) From 994018fb4742c16c43d76a0d547d6add7aa15904 Mon Sep 17 00:00:00 2001 From: 38elements Date: Sun, 24 Jun 2018 01:21:51 +0900 Subject: [PATCH 3/3] fix error message --- packages/test-utils/src/vue-wrapper.js | 6 +++--- packages/test-utils/src/wrapper-array.js | 4 ++-- packages/test-utils/src/wrapper.js | 13 +++++-------- test/specs/vue-wrapper.spec.js | 2 +- test/specs/wrapper-array.spec.js | 2 +- test/specs/wrapper.spec.js | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/test-utils/src/vue-wrapper.js b/packages/test-utils/src/vue-wrapper.js index bd94a0c33..6db1de2d9 100644 --- a/packages/test-utils/src/vue-wrapper.js +++ b/packages/test-utils/src/vue-wrapper.js @@ -12,17 +12,17 @@ export default class VueWrapper extends Wrapper implements BaseWrapper { // $FlowIgnore : issue with defineProperty Object.defineProperty(this, 'vnode', { get: () => vm._vnode, - set: () => throwError(`VueWrapper.vnode is read-only`) + set: () => throwError('wrapper.vnode is read-only') }) // $FlowIgnore Object.defineProperty(this, 'element', { get: () => vm.$el, - set: () => throwError(`VueWrapper.element is read-only`) + set: () => throwError('wrapper.element is read-only') }) // $FlowIgnore Object.defineProperty(this, 'vm', { get: () => vm, - set: () => throwError(`VueWrapper.vm is read-only`) + set: () => throwError('wrapper.vm is read-only') }) if (options.sync) { setWatchersToSync(vm) diff --git a/packages/test-utils/src/wrapper-array.js b/packages/test-utils/src/wrapper-array.js index d69c761da..30e2c76e6 100644 --- a/packages/test-utils/src/wrapper-array.js +++ b/packages/test-utils/src/wrapper-array.js @@ -13,12 +13,12 @@ export default class WrapperArray implements BaseWrapper { // $FlowIgnore Object.defineProperty(this, 'wrappers', { get: () => wrappers, - set: () => throwError(`WrapperArray.wrappers is read-only`) + set: () => throwError('wrapperArray.wrappers is read-only') }) // $FlowIgnore Object.defineProperty(this, 'length', { get: () => length, - set: () => throwError(`WrapperArray.length is read-only`) + set: () => throwError('wrapperArray.length is read-only') }) } diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index f9decf705..8091ea04b 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -24,7 +24,6 @@ import { orderWatchers } from './order-watchers' export default class Wrapper implements BaseWrapper { +vnode: VNode | null; - _vnode: VNode | null; +vm: Component | null; _emitted: { [name: string]: Array> }; _emittedByOrder: Array<{ name: string, args: Array }>; @@ -40,28 +39,27 @@ export default class Wrapper implements BaseWrapper { const element = node instanceof Element ? node : node.elm // Prevent redefine by VueWrapper if (this.constructor.name === 'Wrapper') { - this._vnode = vnode // $FlowIgnore Object.defineProperty(this, 'vnode', { - get: () => this._vnode, - set: () => throwError(`Wrapper.vnode is read-only`) + get: () => vnode, + set: () => throwError('wrapper.vnode is read-only') }) // $FlowIgnore Object.defineProperty(this, 'element', { get: () => element, - set: () => throwError(`Wrapper.element is read-only`) + set: () => throwError('wrapper.element is read-only') }) // $FlowIgnore Object.defineProperty(this, 'vm', { get: () => undefined, - set: () => throwError(`Wrapper.vm is read-only`) + set: () => throwError('wrapper.vm is read-only') }) } const frozenOptions = Object.freeze(options) // $FlowIgnore Object.defineProperty(this, 'options', { get: () => frozenOptions, - set: () => throwError(`${this.constructor.name}.options is read-only`) + set: () => throwError('wrapper.options is read-only') }) if ( this.vnode && @@ -668,7 +666,6 @@ export default class Wrapper implements BaseWrapper { }) // $FlowIgnore : Problem with possibly null this.vm - this._vnode = this.vm._vnode orderWatchers(this.vm || this.vnode.context.$root) Vue.config.silent = originalConfig } diff --git a/test/specs/vue-wrapper.spec.js b/test/specs/vue-wrapper.spec.js index dd847e2f5..4b6cb60b7 100644 --- a/test/specs/vue-wrapper.spec.js +++ b/test/specs/vue-wrapper.spec.js @@ -5,7 +5,7 @@ describeWithShallowAndMount('VueWrapper', mountingMethod => { it(`has the ${property} property which is read-only`, () => { const wrapper = mountingMethod({ template: '

' }) expect(wrapper.constructor.name).to.equal('VueWrapper') - const message = `[vue-test-utils]: VueWrapper.${property} is read-only` + const message = `[vue-test-utils]: wrapper.${property} is read-only` expect(() => { wrapper[property] = 'foo' }) .to.throw() .with.property('message', message) diff --git a/test/specs/wrapper-array.spec.js b/test/specs/wrapper-array.spec.js index 2376d92b8..590210a6d 100644 --- a/test/specs/wrapper-array.spec.js +++ b/test/specs/wrapper-array.spec.js @@ -13,7 +13,7 @@ describeWithShallowAndMount('WrapperArray', mountingMethod => { ['wrappers', 'length'].forEach(property => { it(`has the ${property} property which is read-only`, () => { const wrapperArray = getWrapperArray() - const message = `[vue-test-utils]: WrapperArray.${property} is read-only` + const message = `[vue-test-utils]: wrapperArray.${property} is read-only` expect(() => { wrapperArray[property] = 'foo' }) .to.throw() .with.property('message', message) diff --git a/test/specs/wrapper.spec.js b/test/specs/wrapper.spec.js index 41c82a55b..82848ab74 100644 --- a/test/specs/wrapper.spec.js +++ b/test/specs/wrapper.spec.js @@ -6,7 +6,7 @@ describeWithShallowAndMount('Wrapper', mountingMethod => { const wrapper = mountingMethod({ template: '

' }) .find('p') expect(wrapper.constructor.name).to.equal('Wrapper') - const message = `[vue-test-utils]: Wrapper.${property} is read-only` + const message = `[vue-test-utils]: wrapper.${property} is read-only` expect(() => { wrapper[property] = 'foo' }) .to.throw() .with.property('message', message)