Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add enableAutoUnmount feature #998

Merged
merged 1 commit into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,28 @@ function shallowMount(Component, options?: MountingOptions): VueWrapper

`shallowMount` behaves exactly like `mount`, but it stubs all child components by default. Essentially, `shallowMount(Component)` is an alias of `mount(Component, { shallow: true })`.

## enableAutoUnmount


**Signature:**
```ts
enableAutoUnmount(hook: Function));
disableAutoUnmount(): void;
```

**Details:**

`enableAutoUnmount` allows to automatically destroy Vue wrappers. Destroy logic is passed as callback to `hook` Function.
Common usage is to use `enableAutoUnmount` with teardown helper functions provided by your test framework, such as `afterEach`:

```ts
import { enableAutoUnmount } from '@vue/test-utils'

enableAutoUnmount(afterEach)
```

`disableAutoUnmount` might be useful if you want this behavior only in specific subset of your test suite and you want to explicitly disable this behavior

## flushPromises

**Signature:**
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import { DOMWrapper } from './domWrapper'
import { createWrapperError } from './errorWrapper'
import { config } from './config'
import { flushPromises } from './utils/flushPromises'
import { enableAutoUnmount, disableAutoUnmount } from './utils/autoUnmount'

export {
mount,
shallowMount,
enableAutoUnmount,
disableAutoUnmount,
RouterLinkStub,
VueWrapper,
DOMWrapper,
Expand Down
5 changes: 4 additions & 1 deletion src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
isLegacyFunctionalComponent,
unwrapLegacyVueExtendComponent
} from './utils/vueCompatSupport'
import { trackInstance } from './utils/autoUnmount'

// NOTE this should come from `vue`
type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps
Expand Down Expand Up @@ -452,7 +453,9 @@ export function mount(
return Reflect.has(appRef, property)
}
console.warn = warnSave
return createWrapper(app, appRef, setProps)
const wrapper = createWrapper(app, appRef, setProps)
trackInstance(wrapper)
return wrapper
}

export const shallowMount: typeof mount = (component: any, options?: any) => {
Expand Down
32 changes: 32 additions & 0 deletions src/utils/autoUnmount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ComponentPublicInstance } from 'vue'
import type { VueWrapper } from '../vueWrapper'

let isEnabled = false
const wrapperInstances: VueWrapper<ComponentPublicInstance>[] = []

export function disableAutoUnmount() {
isEnabled = false
wrapperInstances.length = 0
}

export function enableAutoUnmount(hook: Function) {
if (isEnabled) {
throw new Error('enableAutoUnmount cannot be called more than once')
}

isEnabled = true

hook(() => {
wrapperInstances.forEach((wrapper: VueWrapper<ComponentPublicInstance>) => {
wrapper.unmount()
})

wrapperInstances.length = 0
})
}

export function trackInstance(wrapper: VueWrapper<ComponentPublicInstance>) {
if (!isEnabled) return

wrapperInstances.push(wrapper)
}
37 changes: 37 additions & 0 deletions tests/autoUnmount.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { mount, enableAutoUnmount, disableAutoUnmount } from '../src'

describe('enableAutoUnmount', () => {
beforeEach(() => {
disableAutoUnmount()
})

it('calls the hook function', () => {
const hookMock = jest.fn()

enableAutoUnmount(hookMock)

expect(hookMock).toHaveBeenCalledWith(expect.any(Function))
})

it('uses the hook function to unmount wrappers', () => {
const hookMock = jest.fn()

enableAutoUnmount(hookMock)
const [unmountFn] = hookMock.mock.calls[0]

const wrapper = mount({ template: '<p>test</p>' })
jest.spyOn(wrapper, 'unmount')

unmountFn()

expect(wrapper.unmount).toHaveBeenCalledTimes(1)
})

it('cannot be called twice', () => {
const noop = () => {}

enableAutoUnmount(noop)

expect(() => enableAutoUnmount(noop)).toThrow()
})
})