Skip to content

Commit fcde128

Browse files
committed
feat: add unmount to wrapper
1 parent fc96ca3 commit fcde128

File tree

3 files changed

+61
-15
lines changed

3 files changed

+61
-15
lines changed

src/mount.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ export function mount(
101101
props[k] = v
102102
}
103103

104-
return app.$nextTick()
104+
return vm.$nextTick()
105105
}
106106

107-
// create the vm
108-
const vm = createApp(Parent)
107+
// create the app
108+
const app = createApp(Parent)
109109

110110
// global mocks mixin
111111
if (options?.global?.mocks) {
@@ -117,40 +117,40 @@ export function mount(
117117
}
118118
}
119119

120-
vm.mixin(mixin)
120+
app.mixin(mixin)
121121
}
122122

123123
// use and plugins from mounting options
124124
if (options?.global?.plugins) {
125-
for (const use of options?.global?.plugins) vm.use(use)
125+
for (const use of options?.global?.plugins) app.use(use)
126126
}
127127

128128
// use any mixins from mounting options
129129
if (options?.global?.mixins) {
130-
for (const mixin of options?.global?.mixins) vm.mixin(mixin)
130+
for (const mixin of options?.global?.mixins) app.mixin(mixin)
131131
}
132132

133133
if (options?.global?.components) {
134134
for (const key of Object.keys(options?.global?.components))
135-
vm.component(key, options.global.components[key])
135+
app.component(key, options.global.components[key])
136136
}
137137

138138
if (options?.global?.directives) {
139139
for (const key of Object.keys(options?.global?.directives))
140-
vm.directive(key, options.global.directives[key])
140+
app.directive(key, options.global.directives[key])
141141
}
142142

143143
// provide any values passed via provides mounting option
144144
if (options?.global?.provide) {
145145
for (const key of Reflect.ownKeys(options.global.provide)) {
146146
// @ts-ignore: https://github.com/microsoft/TypeScript/issues/1863
147-
vm.provide(key, options.global.provide[key])
147+
app.provide(key, options.global.provide[key])
148148
}
149149
}
150150

151151
// add tracking for emitted events
152152
const { emitMixin, events } = createEmitMixin()
153-
vm.mixin(emitMixin)
153+
app.mixin(emitMixin)
154154

155155
// stubs
156156
if (options?.global?.stubs) {
@@ -160,7 +160,7 @@ export function mount(
160160
}
161161

162162
// mount the app!
163-
const app = vm.mount(el)
163+
const vm = app.mount(el)
164164

165-
return createWrapper(app, events, setProps)
165+
return createWrapper(app, vm, events, setProps)
166166
}

src/vue-wrapper.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ComponentPublicInstance, nextTick } from 'vue'
1+
import { ComponentPublicInstance, nextTick, App } from 'vue'
22
import { ShapeFlags } from '@vue/shared'
33

44
import { DOMWrapper } from './dom-wrapper'
@@ -9,15 +9,18 @@ import { MOUNT_ELEMENT_ID } from './constants'
99
export class VueWrapper<T extends ComponentPublicInstance>
1010
implements WrapperAPI {
1111
private componentVM: T
12+
private __app: App
1213
private __emitted: Record<string, unknown[]> = {}
1314
private __vm: ComponentPublicInstance
1415
private __setProps: (props: Record<string, any>) => void
1516

1617
constructor(
18+
app: App,
1719
vm: ComponentPublicInstance,
1820
events: Record<string, unknown[]>,
1921
setProps: (props: Record<string, any>) => void
2022
) {
23+
this.__app = app
2124
this.__vm = vm
2225
this.__setProps = setProps
2326
this.componentVM = this.__vm.$refs['VTU_COMPONENT'] as T
@@ -109,12 +112,20 @@ export class VueWrapper<T extends ComponentPublicInstance>
109112
const rootElementWrapper = new DOMWrapper(this.element)
110113
return rootElementWrapper.trigger(eventString)
111114
}
115+
116+
unmount() {
117+
if (this.parentElement) {
118+
this.parentElement.removeChild(this.element)
119+
}
120+
this.__app.unmount(this.element)
121+
}
112122
}
113123

114124
export function createWrapper<T extends ComponentPublicInstance>(
125+
app: App,
115126
vm: ComponentPublicInstance,
116127
events: Record<string, unknown[]>,
117128
setProps: (props: Record<string, any>) => void
118129
): VueWrapper<T> {
119-
return new VueWrapper<T>(vm, events, setProps)
130+
return new VueWrapper<T>(app, vm, events, setProps)
120131
}

tests/lifecycle.spec.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { defineComponent, h, onMounted, nextTick, onBeforeMount } from 'vue'
1+
import {
2+
defineComponent,
3+
h,
4+
onMounted,
5+
nextTick,
6+
onBeforeMount,
7+
onUnmounted,
8+
onBeforeUnmount
9+
} from 'vue'
210

311
import { mount } from '../src'
412

@@ -24,4 +32,31 @@ describe('lifecycles', () => {
2432
expect(onBeforeMountFn).toHaveBeenCalled()
2533
expect(onBeforeMountFn).toHaveBeenCalled()
2634
})
35+
36+
it('calls onUnmounted', async () => {
37+
const beforeUnmountFn = jest.fn()
38+
const onBeforeUnmountFn = jest.fn()
39+
const onUnmountFn = jest.fn()
40+
const Component = defineComponent({
41+
beforeUnmount: beforeUnmountFn,
42+
setup() {
43+
onUnmounted(onUnmountFn)
44+
onBeforeUnmount(onBeforeUnmountFn)
45+
46+
return () => h('div')
47+
}
48+
})
49+
50+
const wrapper = mount(Component)
51+
await nextTick()
52+
expect(beforeUnmountFn).not.toHaveBeenCalled()
53+
expect(onBeforeUnmountFn).not.toHaveBeenCalled()
54+
expect(onUnmountFn).not.toHaveBeenCalled()
55+
56+
wrapper.unmount()
57+
58+
expect(beforeUnmountFn).toHaveBeenCalled()
59+
expect(onBeforeUnmountFn).toHaveBeenCalled()
60+
expect(onUnmountFn).toHaveBeenCalled()
61+
})
2762
})

0 commit comments

Comments
 (0)