Skip to content

Commit

Permalink
test: use sandbox to avoid memory leaks in test (#1128)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyerburgh authored Feb 3, 2019
1 parent 85a972c commit 0c07653
Show file tree
Hide file tree
Showing 30 changed files with 305 additions and 290 deletions.
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"test:unit:debug": "npm run build:test && node --inspect-brk node_modules/.bin/mocha-webpack --webpack-config test/setup/webpack.test.config.js test/specs --recursive --require test/setup/mocha.setup.js",
"test:unit:karma": "npm run build:test && TARGET=browser karma start test/setup/karma.conf.js --single-run",
"test:unit:node": "npm run build:test && npm run test:unit:node:only",
"test:unit:node:only": "TEST_ENV=node mocha-webpack --webpack-config test/setup/webpack.test.config.js test/specs --recursive --require test/setup/mocha.setup.js",
"test:unit:node:only": "cross-env TEST_ENV=node mocha-webpack --webpack-config test/setup/webpack.test.config.js test/specs --recursive --require test/setup/mocha.setup.js",
"test:types": "tsc -p packages/test-utils/types && tsc -p packages/server-test-utils/types"
},
"devDependencies": {
Expand Down Expand Up @@ -54,18 +54,18 @@
"karma": "^1.7.0",
"karma-mocha": "^1.3.0",
"karma-phantomjs-launcher": "^1.0.4",
"karma-sinon-chai": "^1.3.1",
"karma-sinon-chai": "^2.0.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "^0.0.31",
"karma-webpack": "^2.0.3",
"lerna": "2",
"markdown-it-include": "^1.0.0",
"mocha": "^3.5.0",
"mocha": "^5.2.0",
"mocha-webpack": "^1.0.1",
"prettier": "^1.16.0",
"rollup": "^0.58.2",
"sinon": "^2.3.2",
"sinon-chai": "^2.10.0",
"sinon": "^7.2.3",
"sinon-chai": "^3.3.0",
"typescript": "^3.0.1",
"vee-validate": "^2.1.3",
"vue": "^2.5.22",
Expand Down
11 changes: 8 additions & 3 deletions packages/create-instance/create-component-stubs.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ function resolveOptions(component, _Vue) {
return {}
}

return isConstructor(component)
? component.options
: _Vue.extend(component).options
if (isConstructor(component)) {
return component.options
}
const options = _Vue.extend(component).options
component._Ctor = {}

return options
}

export function createStubFromComponent(
Expand Down Expand Up @@ -165,6 +169,7 @@ export function createStubsFromStubsObject(
}

acc[stubName] = stub
stub._Ctor = {}

return acc
}, {})
Expand Down
2 changes: 1 addition & 1 deletion packages/create-instance/create-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function createInstance(
// make sure all extends are based on this instance

const Constructor = _Vue.extend(componentOptions).extend(instanceOptions)

componentOptions._Ctor = {}
Constructor.options._base = _Vue

const scopedSlots = createScopedSlots(options.scopedSlots, _Vue)
Expand Down
1 change: 1 addition & 0 deletions packages/create-instance/patch-create-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function shouldExtend(component, _Vue) {
function extend(component, _Vue) {
const componentOptions = component.options ? component.options : component
const stub = _Vue.extend(componentOptions)
componentOptions._Ctor = {}
stub.options.$_vueTestUtils_original = component
stub.options._base = _Vue
return stub
Expand Down
1 change: 0 additions & 1 deletion test/resources/components/component-with-events.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export default {
mousedownHandler(event) {
if (event.button === 0) {
this.clickHandler()
console.info(event.defaultPrevented)
}
},
toggleActive() {
Expand Down
4 changes: 2 additions & 2 deletions test/resources/components/recursive-component.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div>
<recursive-component
v-for="item in items"
:key="item"
v-for="(item, i) in items"
:key="i"
:items="items ? items[0] : []"
>{{ something }}</recursive-component
>
Expand Down
9 changes: 5 additions & 4 deletions test/specs/components/TransitionStub.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { TransitionStub } from '~vue/test-utils'
import { itDoNotRunIf } from 'conditional-specs'

describeWithShallowAndMount('TransitionStub', mountingMethod => {
let consoleError
const sandbox = sinon.createSandbox()

beforeEach(() => {
consoleError = sinon.stub(console, 'error')
sandbox.stub(console, 'error').callThrough()
})

afterEach(() => {
consoleError.restore()
sandbox.reset()
sandbox.restore()
})

it('update synchronously when used as stubs for Transition', () => {
Expand Down Expand Up @@ -76,7 +77,7 @@ describeWithShallowAndMount('TransitionStub', mountingMethod => {
transition: TransitionStub
}
})
expect(consoleError).calledWith(msg)
expect(console.error).calledWith(msg)
})

it('handles keyed transitions', () => {
Expand Down
16 changes: 10 additions & 6 deletions test/specs/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ import {
} from '~vue/test-utils'

describeWithShallowAndMount('config', mountingMethod => {
let configStubsSave, configLogSave, configSilentSave
const sandbox = sinon.createSandbox()
let configStubsSave
let configLogSave
let configSilentSave

beforeEach(() => {
configStubsSave = config.stubs
configLogSave = config.logModifiedComponents
configSilentSave = config.silent
sinon.stub(console, 'error').callThrough()
sandbox.stub(console, 'error').callThrough()
})

afterEach(() => {
config.stubs = configStubsSave
config.logModifiedComponents = configLogSave
config.silent = configSilentSave
console.error.restore()
sandbox.reset()
sandbox.restore()
})

itDoNotRunIf(
Expand Down Expand Up @@ -113,7 +117,7 @@ describeWithShallowAndMount('config', mountingMethod => {
const testComponent = {
template: `
<div>
<transition-group><p /><p /></transition-group>
<transition-group><p key="1"/><p key="2" /></transition-group>
</div>
`
}
Expand All @@ -135,7 +139,7 @@ describeWithShallowAndMount('config', mountingMethod => {
wrapper.setProps({
prop1: 'new value'
})
expect(console.error).not.calledWith(sinon.match('[Vue warn]'))
expect(console.error).not.calledWith(sandbox.match('[Vue warn]'))
})

it('does throw Vue warning when silent is set to false', () => {
Expand All @@ -151,6 +155,6 @@ describeWithShallowAndMount('config', mountingMethod => {
wrapper.setProps({
prop1: 'new value'
})
expect(console.error).calledWith(sinon.match('[Vue warn]'))
expect(console.error).calledWith(sandbox.match('[Vue warn]'))
})
})
7 changes: 4 additions & 3 deletions test/specs/error-wrapper.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { compileToFunctions } from 'vue-template-compiler'
import { describeWithShallowAndMount } from '~resources/utils'

describeWithShallowAndMount('ErrorWrapper', mountingMethod => {
Expand Down Expand Up @@ -36,10 +35,12 @@ describeWithShallowAndMount('ErrorWrapper', mountingMethod => {
]
methods.forEach(method => {
it(`${method} throws error when called`, () => {
const compiled = compileToFunctions('<p />')
const TestComponent = {
template: '<p />'
}
const selector = 'div'
const message = `[vue-test-utils]: find did not return ${selector}, cannot call ${method}() on empty Wrapper`
const wrapper = mountingMethod(compiled)
const wrapper = mountingMethod(TestComponent)
const error = wrapper.find(selector)
expect(error.constructor.name).to.equal('ErrorWrapper')
expect(() => error[method]())
Expand Down
24 changes: 13 additions & 11 deletions test/specs/mount.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import { describeRunIf, itDoNotRunIf, itSkipIf } from 'conditional-specs'
import Vuex from 'vuex'

describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
const sandbox = sinon.createSandbox()
const windowSave = window

beforeEach(() => {
sinon.stub(console, 'error').callThrough()
sandbox.stub(console, 'error').callThrough()
})

afterEach(() => {
window = windowSave // eslint-disable-line no-native-reassign
console.error.restore()
sandbox.reset()
sandbox.restore()
})

it('returns new VueWrapper with mounted Vue instance if no options are passed', () => {
Expand Down Expand Up @@ -101,7 +103,7 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
'handles extended components added to Vue constructor',
() => {
const ChildComponent = Vue.extend({
template: '<div />',
render: h => h('div'),
mounted() {
this.$route.params
}
Expand All @@ -126,10 +128,11 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
)

it('does not use cached component', () => {
ComponentWithMixin.methods.someMethod = sinon.stub()
sandbox.stub(ComponentWithMixin.methods, 'someMethod')
mount(ComponentWithMixin)
expect(ComponentWithMixin.methods.someMethod.callCount).to.equal(1)
ComponentWithMixin.methods.someMethod = sinon.stub()
ComponentWithMixin.methods.someMethod.restore()
sandbox.stub(ComponentWithMixin.methods, 'someMethod')
mount(ComponentWithMixin)
expect(ComponentWithMixin.methods.someMethod.callCount).to.equal(1)
})
Expand All @@ -138,7 +141,6 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
if (
!(navigator.userAgent.includes && navigator.userAgent.includes('node.js'))
) {
console.log('window read only. skipping test ...')
return
}

Expand All @@ -160,7 +162,7 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
})

itDoNotRunIf(vueVersion < 2.3, 'overrides methods', () => {
const stub = sinon.stub()
const stub = sandbox.stub()
const TestComponent = Vue.extend({
template: '<div />',
methods: {
Expand All @@ -179,8 +181,8 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
})

it.skip('overrides component prototype', () => {
const mountSpy = sinon.spy()
const destroySpy = sinon.spy()
const mountSpy = sandbox.spy()
const destroySpy = sandbox.spy()
const Component = Vue.extend({})
const {
$mount: originalMount,
Expand Down Expand Up @@ -233,7 +235,7 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
it('deletes mounting options before passing options to component', () => {
const wrapper = mount(
{
render: h => h('div')
template: '<div />'
},
{
provide: {
Expand All @@ -248,7 +250,7 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
},
localVue: createLocalVue(),
stubs: {
prop: 'val'
prop: { template: '<div />' }
},
attrs: {
prop: 'val'
Expand Down
8 changes: 5 additions & 3 deletions test/specs/mounting-options/attrs.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { compileToFunctions } from 'vue-template-compiler'
import { attrsSupported } from '~resources/utils'
import {
describeWithMountingMethods,
Expand All @@ -15,7 +14,10 @@ describeWithMountingMethods('options.attrs', mountingMethod => {
'handles inherit attrs',
() => {
if (!attrsSupported) return
const wrapper = mountingMethod(compileToFunctions('<p :id="anAttr" />'), {
const TestComponent = {
template: '<p :id="$attrs.anAttr" />'
}
const wrapper = mountingMethod(TestComponent, {
attrs: {
anAttr: 'an attribute'
}
Expand All @@ -29,7 +31,7 @@ describeWithMountingMethods('options.attrs', mountingMethod => {
mountingMethod.name === 'renderToString' || vueVersion < 2.5,
'defines attrs as empty object even when not passed',
() => {
const wrapper = mountingMethod(compileToFunctions('<p />'))
const wrapper = mountingMethod({ template: '<p />' })
expect(wrapper.vm.$attrs).to.deep.equal({})
}
)
Expand Down
7 changes: 4 additions & 3 deletions test/specs/mounting-options/listeners.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { compileToFunctions } from 'vue-template-compiler'
import { listenersSupported } from '~resources/utils'
import {
describeWithShallowAndMount,
Expand All @@ -14,7 +13,9 @@ describeWithShallowAndMount('options.listeners', mountingMethod => {
() => {
const aListener = () => {}
const wrapper = mountingMethod(
compileToFunctions('<p :id="aListener" />'),
{
template: '<p :id="$listeners.aListener" />'
},
{
listeners: {
aListener
Expand Down Expand Up @@ -56,7 +57,7 @@ describeWithShallowAndMount('options.listeners', mountingMethod => {
vueVersion < 2.5,
'defines listeners as empty object even when not passed',
() => {
const wrapper = mountingMethod(compileToFunctions('<p />'))
const wrapper = mountingMethod({ template: '<p />' })
expect(wrapper.vm.$listeners).to.deep.equal({})
}
)
Expand Down
2 changes: 1 addition & 1 deletion test/specs/mounting-options/localVue.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describeWithMountingMethods('options.localVue', mountingMethod => {
const Extends = {
template: '<div />',
created() {
console.log(this.$route.params)
this.$route.params
}
}
const TestComponent = {
Expand Down
8 changes: 5 additions & 3 deletions test/specs/mounting-options/mocks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import { describeWithMountingMethods, vueVersion } from '~resources/utils'
import { itDoNotRunIf, itSkipIf, itRunIf } from 'conditional-specs'

describeWithMountingMethods('options.mocks', mountingMethod => {
const sandbox = sinon.createSandbox()
let configMocksSave

beforeEach(() => {
configMocksSave = config.mocks
config.mocks = {}
sinon.stub(console, 'error')
sandbox.stub(console, 'error').callThrough()
})

afterEach(() => {
config.mocks = configMocksSave
console.error.restore()
sandbox.reset()
sandbox.restore()
})

it('adds variables to vm when passed', () => {
Expand Down Expand Up @@ -69,7 +71,7 @@ describeWithMountingMethods('options.mocks', mountingMethod => {
mountingMethod.name === 'renderToString',
'adds variables as reactive properties to vm when passed',
() => {
const stub = sinon.stub()
const stub = sandbox.stub()
const $reactiveMock = { value: 'value' }
const wrapper = mountingMethod(
{
Expand Down
Loading

0 comments on commit 0c07653

Please sign in to comment.