From ef6e4c066ec633de36f17bff55ef5f372a2115ef Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Wed, 8 Apr 2020 00:22:28 +1000 Subject: [PATCH 1/4] feat: mocks mounting option --- src/mount.ts | 15 ++++++++++++++- tests/mountingOptions/mocks.spec.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/mountingOptions/mocks.spec.ts diff --git a/src/mount.ts b/src/mount.ts index e32a99c64..54115fda7 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -8,7 +8,8 @@ import { ComponentOptions, Plugin, Directive, - Component + Component, + getCurrentInstance } from 'vue' import { VueWrapper, createWrapper } from './vue-wrapper' @@ -21,6 +22,7 @@ type Slot = VNode | string | { render: Function } interface MountingOptions { data?: () => Record props?: Props + mocks?: Record slots?: { default?: Slot [key: string]: Slot @@ -77,6 +79,17 @@ export function mount

( // create the vm const vm = createApp(Parent(options && options.props)) + if (options?.mocks) { + const mixin = { + beforeCreate() { + for (const [k, v] of Object.entries(options.mocks)) { + this[k] = v + } + } + } + + vm.mixin(mixin) + } // use and plugins from mounting options if (options?.global?.plugins) { diff --git a/tests/mountingOptions/mocks.spec.ts b/tests/mountingOptions/mocks.spec.ts new file mode 100644 index 000000000..1d3fdb654 --- /dev/null +++ b/tests/mountingOptions/mocks.spec.ts @@ -0,0 +1,28 @@ +import { mount } from '../../src' + +describe('mocks', () => { + it('mocks a vuex store', async () => { + const Foo = { + template: ` +

+ count: {{ $store.state.count }} +
+ ` + } + const $store = { + state: { + count: 1 + }, + dispatch: jest.fn() + } + + const wrapper = mount(Foo, { + mocks: { $store } + }) + + expect(wrapper.html()).toContain('count: 1') + await wrapper.find('button').trigger('click') + expect($store.dispatch).toHaveBeenCalledWith('inc') + }) +}) From 33bf174b9a483002069dfb98129b521d8e461cc6 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Wed, 8 Apr 2020 00:26:39 +1000 Subject: [PATCH 2/4] refactor: mocks to global --- src/mount.ts | 6 +++--- tests/mountingOptions/mocks.spec.ts | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index 54115fda7..aefc649e7 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -22,7 +22,6 @@ type Slot = VNode | string | { render: Function } interface MountingOptions { data?: () => Record props?: Props - mocks?: Record slots?: { default?: Slot [key: string]: Slot @@ -30,6 +29,7 @@ interface MountingOptions { global?: { plugins?: Plugin[] mixins?: ComponentOptions[] + mocks?: Record provide?: Record components?: Record directives?: Record @@ -79,10 +79,10 @@ export function mount

( // create the vm const vm = createApp(Parent(options && options.props)) - if (options?.mocks) { + if (options?.global?.mocks) { const mixin = { beforeCreate() { - for (const [k, v] of Object.entries(options.mocks)) { + for (const [k, v] of Object.entries(options.global?.mocks)) { this[k] = v } } diff --git a/tests/mountingOptions/mocks.spec.ts b/tests/mountingOptions/mocks.spec.ts index 1d3fdb654..1014520f7 100644 --- a/tests/mountingOptions/mocks.spec.ts +++ b/tests/mountingOptions/mocks.spec.ts @@ -18,7 +18,9 @@ describe('mocks', () => { } const wrapper = mount(Foo, { - mocks: { $store } + global: { + mocks: { $store } + } }) expect(wrapper.html()).toContain('count: 1') From 653285e8dd14b58e1514166da5e8a9df2c6c2fc7 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Wed, 8 Apr 2020 00:31:56 +1000 Subject: [PATCH 3/4] refactor: add comment --- src/mount.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mount.ts b/src/mount.ts index aefc649e7..bb4eec1be 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -79,6 +79,8 @@ export function mount

( // create the vm const vm = createApp(Parent(options && options.props)) + + // global mocks mixin if (options?.global?.mocks) { const mixin = { beforeCreate() { From a2dd554865ff39c42c1e055b6f63ae56b6afac1b Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Wed, 8 Apr 2020 21:04:41 +1000 Subject: [PATCH 4/4] tests: demo mocking router --- src/components/RouterLinkStub.ts | 17 ++++++++++ src/index.ts | 3 +- src/mount.ts | 3 +- tests/mountingOptions/mocks.spec.ts | 48 ++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/components/RouterLinkStub.ts diff --git a/src/components/RouterLinkStub.ts b/src/components/RouterLinkStub.ts new file mode 100644 index 000000000..255253a91 --- /dev/null +++ b/src/components/RouterLinkStub.ts @@ -0,0 +1,17 @@ +import { defineComponent, h } from 'vue' + +// TODO: Borrow typings from vue-router-next +export const RouterLinkStub = defineComponent({ + name: 'RouterLinkStub', + + props: { + to: { + type: [String, Object], + required: true + } + }, + + render() { + return h('a', undefined, this.$slots.default()) + } +}) diff --git a/src/index.ts b/src/index.ts index f3289f47a..891f92be2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ import { mount } from './mount' +import { RouterLinkStub } from './components/RouterLinkStub' -export { mount } +export { mount, RouterLinkStub } diff --git a/src/mount.ts b/src/mount.ts index bb4eec1be..89f903646 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -31,7 +31,8 @@ interface MountingOptions { mixins?: ComponentOptions[] mocks?: Record provide?: Record - components?: Record + // TODO how to type `defineComponent`? Using `any` for now. + components?: Record directives?: Record } stubs?: Record diff --git a/tests/mountingOptions/mocks.spec.ts b/tests/mountingOptions/mocks.spec.ts index 1014520f7..da47e89e6 100644 --- a/tests/mountingOptions/mocks.spec.ts +++ b/tests/mountingOptions/mocks.spec.ts @@ -1,4 +1,4 @@ -import { mount } from '../../src' +import { mount, RouterLinkStub } from '../../src' describe('mocks', () => { it('mocks a vuex store', async () => { @@ -27,4 +27,50 @@ describe('mocks', () => { await wrapper.find('button').trigger('click') expect($store.dispatch).toHaveBeenCalledWith('inc') }) + + it('mocks vue-router', async () => { + const Foo = { + template: ` +

+ Go to post: {{ id }} + +
+ `, + computed: { + url() { + return `/posts/${this.$route.params.id}` + }, + id() { + return this.$route.params.id + } + }, + methods: { + submit() { + this.$router.push(`/posts/${this.id}`) + } + } + } + + const $router = { + push: jest.fn() + } + const $route = { + params: { + id: 1 + } + } + + const wrapper = mount(Foo, { + global: { + components: { + RouterLink: RouterLinkStub + }, + mocks: { $route, $router } + } + }) + + expect(wrapper.html()).toContain('Go to post: 1') + await wrapper.find('button').trigger('click') + expect($router.push).toHaveBeenCalledWith('/posts/1') + }) })