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

fix: vm should be properly typed #63

Merged
merged 1 commit into from
Apr 15, 2020
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
21 changes: 16 additions & 5 deletions src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import {
Plugin,
Directive,
Component,
reactive
reactive,
ComponentPublicInstance
} from 'vue'

import { createWrapper } from './vue-wrapper'
import { createWrapper, VueWrapper } from './vue-wrapper'
import { createEmitMixin } from './emitMixin'
import { createDataMixin } from './dataMixin'
import { MOUNT_ELEMENT_ID } from './constants'
Expand All @@ -37,7 +38,14 @@ interface MountingOptions {
stubs?: Record<string, any>
}

export function mount(originalComponent: any, options?: MountingOptions) {
export function mount<T extends any>(
originalComponent: any,
options?: MountingOptions
): VueWrapper<any>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @cexbrayat I will give this a quick test tmr and get it merged.

While we are here, can we get typings in the props mounting options? I was able to do that in an experiment I built prior to this, found here

Eg then we could do

mount(Foo, {
  props: { 
    bar: 'sadf' // <= can we get typesafety here? that would be cool as
  }
})

If this is difficult to accomplish don't worry about it too much for now, but I agree, we should provide as many typings as possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eg: component: new () => ComponentPublicInstance<P> (or something)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll try to look into it soon, and I'll open a dedicated PR 👌

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lmiller1990 FYI I added some typings tests using tsd in #72 , improved the typing of vm some more in #73 and started working on properly typings the props options in #74

export function mount<T extends ComponentPublicInstance>(
originalComponent: new () => T,
options?: MountingOptions
): VueWrapper<T> {
const component = { ...originalComponent }

// Reset the document.body
Expand All @@ -63,7 +71,10 @@ export function mount(originalComponent: any, options?: MountingOptions) {
// override component data with mounting options data
if (options?.data) {
const dataMixin = createDataMixin(options.data())
component.mixins = [...(component.mixins || []), dataMixin]
;(component as any).mixins = [
...((component as any).mixins || []),
dataMixin
]
}

// we define props as reactive so that way when we update them with `setProps`
Expand Down Expand Up @@ -136,5 +147,5 @@ export function mount(originalComponent: any, options?: MountingOptions) {
// mount the app!
const app = vm.mount(el)

return createWrapper(app, events, setProps)
return createWrapper<T>(app, events, setProps)
}
17 changes: 8 additions & 9 deletions src/vue-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { WrapperAPI } from './types'
import { ErrorWrapper } from './error-wrapper'
import { MOUNT_ELEMENT_ID } from './constants'

export class VueWrapper implements WrapperAPI {
private componentVM: ComponentPublicInstance
export class VueWrapper<T extends ComponentPublicInstance>
implements WrapperAPI {
private componentVM: T
private __emitted: Record<string, unknown[]> = {}
private __vm: ComponentPublicInstance
private __setProps: (props: Record<string, any>) => void
Expand All @@ -19,9 +20,7 @@ export class VueWrapper implements WrapperAPI {
) {
this.__vm = vm
this.__setProps = setProps
this.componentVM = this.__vm.$refs[
'VTU_COMPONENT'
] as ComponentPublicInstance
this.componentVM = this.__vm.$refs['VTU_COMPONENT'] as T
this.__emitted = events
}

Expand All @@ -43,7 +42,7 @@ export class VueWrapper implements WrapperAPI {
return this.hasMultipleRoots ? this.parentElement : this.componentVM.$el
}

get vm(): ComponentPublicInstance {
get vm(): T {
return this.componentVM
}

Expand Down Expand Up @@ -106,10 +105,10 @@ export class VueWrapper implements WrapperAPI {
}
}

export function createWrapper(
export function createWrapper<T extends ComponentPublicInstance>(
vm: ComponentPublicInstance,
events: Record<string, unknown[]>,
setProps: (props: Record<string, any>) => void
): VueWrapper {
return new VueWrapper(vm, events, setProps)
): VueWrapper<T> {
return new VueWrapper<T>(vm, events, setProps)
}
11 changes: 8 additions & 3 deletions tests/vm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ describe('vm', () => {
setup() {
const msg = 'hello'
const isEnabled = ref(true)
return { msg, isEnabled }
const toggle = () => (isEnabled.value = !isEnabled.value)
return { msg, isEnabled, toggle }
}
})

const wrapper = mount(Component)

expect((wrapper.vm as any).msg).toBe('hello')
expect((wrapper.vm as any).isEnabled).toBe(true)
expect(wrapper.vm.msg).toBe('hello')
expect(wrapper.vm.isEnabled).toBe(true)

wrapper.vm.toggle()

expect(wrapper.vm.isEnabled).toBe(false)
})
})