From b8f3c75ff70a3e9bdb9294de504af762f73880aa Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Thu, 26 Mar 2020 17:47:01 +0200 Subject: [PATCH 01/10] feat: add globalProperties to mountingOptions --- src/mount.ts | 8 ++++++++ tests/mountingOptions/globalProperties.spec.ts | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/mountingOptions/globalProperties.spec.ts diff --git a/src/mount.ts b/src/mount.ts index d0394f023..ccfa5dabc 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -39,6 +39,7 @@ interface MountingOptions { directives?: Record } stubs?: Record + globalProperties?: Record } export function mount( @@ -144,6 +145,13 @@ export function mount( } } + // mock globally available properties + if (options?.globalProperties) { + Object.entries(options.globalProperties).forEach(([key, value]) => { + vm.config.globalProperties[key] = value + }) + } + // add tracking for emitted events const { emitMixin, events } = createEmitMixin() vm.mixin(emitMixin) diff --git a/tests/mountingOptions/globalProperties.spec.ts b/tests/mountingOptions/globalProperties.spec.ts new file mode 100644 index 000000000..58b50dff2 --- /dev/null +++ b/tests/mountingOptions/globalProperties.spec.ts @@ -0,0 +1,18 @@ +import { h } from 'vue' +import { mount } from '../../src' + +describe('globalProperties', () => { + it('adds globally available properties to the component', () => { + const Component = { + render() { + return h('div', this.foo) + } + } + const wrapper = mount(Component, { + globalProperties: { + foo: 'bar' + } + }) + expect(wrapper.html()).toEqual('
bar
') + }) +}) From 9921db4b0267478be60897bbe10b53ee7e78c755 Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Sat, 11 Apr 2020 17:52:07 +0300 Subject: [PATCH 02/10] refactor: move globalProperties to global property --- src/mount.ts | 6 +++--- tests/mountingOptions/globalProperties.spec.ts | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index ccfa5dabc..5ed66281f 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -37,9 +37,9 @@ interface MountingOptions { // TODO how to type `defineComponent`? Using `any` for now. components?: Record directives?: Record + globalProperties?: Record } stubs?: Record - globalProperties?: Record } export function mount( @@ -146,8 +146,8 @@ export function mount( } // mock globally available properties - if (options?.globalProperties) { - Object.entries(options.globalProperties).forEach(([key, value]) => { + if (options?.global?.globalProperties) { + Object.entries(options.global.globalProperties).forEach(([key, value]) => { vm.config.globalProperties[key] = value }) } diff --git a/tests/mountingOptions/globalProperties.spec.ts b/tests/mountingOptions/globalProperties.spec.ts index 58b50dff2..2754bac75 100644 --- a/tests/mountingOptions/globalProperties.spec.ts +++ b/tests/mountingOptions/globalProperties.spec.ts @@ -9,8 +9,10 @@ describe('globalProperties', () => { } } const wrapper = mount(Component, { - globalProperties: { - foo: 'bar' + global: { + globalProperties: { + foo: 'bar' + } } }) expect(wrapper.html()).toEqual('
bar
') From 3ffd3ec70a0f76d440deeb0ac62c825594aa9487 Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Mon, 13 Apr 2020 00:39:22 +0300 Subject: [PATCH 03/10] feat: add global config --- package.json | 3 ++ src/config.ts | 5 ++++ src/index.ts | 3 +- src/mount.ts | 55 ++++++++++++++-------------------- src/types.ts | 12 ++++++++ src/utils.ts | 17 +++++++++++ tests/config.spec.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 33 deletions(-) create mode 100644 src/config.ts create mode 100644 tests/config.spec.ts diff --git a/package.json b/package.json index cbf109568..482130145 100644 --- a/package.json +++ b/package.json @@ -61,5 +61,8 @@ "*.ts": [ "prettier --parser=typescript --write" ] + }, + "dependencies": { + "lodash": "^4.17.15" } } diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 000000000..0492584fc --- /dev/null +++ b/src/config.ts @@ -0,0 +1,5 @@ +import { globalMountOptions } from './types' + +export const config: { global: globalMountOptions } = { + global: {} +} diff --git a/src/index.ts b/src/index.ts index 891f92be2..977786aa7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import { mount } from './mount' import { RouterLinkStub } from './components/RouterLinkStub' +import { config } from './config' -export { mount, RouterLinkStub } +export { mount, RouterLinkStub, config } diff --git a/src/mount.ts b/src/mount.ts index 5ed66281f..8ca2156f2 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -4,14 +4,13 @@ import { VNode, defineComponent, VNodeNormalizedChildren, - ComponentOptions, transformVNodeArgs, - Plugin, - Directive, - Component, reactive, ComponentPublicInstance } from 'vue' +import { config } from './config' +import { globalMountOptions } from './types' +import { mergeGlobalProperties } from './utils' import { createWrapper, VueWrapper } from './vue-wrapper' import { createEmitMixin } from './emitMixin' @@ -28,17 +27,7 @@ interface MountingOptions { default?: Slot [key: string]: Slot } - global?: { - plugins?: Plugin[] - mixins?: ComponentOptions[] - mocks?: Record - stubs?: Record - provide?: Record - // TODO how to type `defineComponent`? Using `any` for now. - components?: Record - directives?: Record - globalProperties?: Record - } + global?: globalMountOptions stubs?: Record } @@ -104,11 +93,13 @@ export function mount( // create the vm const vm = createApp(Parent) + const global = mergeGlobalProperties(config.global, options?.global) + // global mocks mixin - if (options?.global?.mocks) { + if (global?.mocks) { const mixin = { beforeCreate() { - for (const [k, v] of Object.entries(options.global?.mocks)) { + for (const [k, v] of Object.entries(global.mocks)) { this[k] = v } } @@ -118,36 +109,36 @@ export function mount( } // use and plugins from mounting options - if (options?.global?.plugins) { - for (const use of options?.global?.plugins) vm.use(use) + if (global?.plugins) { + for (const use of global.plugins) vm.use(use) } // use any mixins from mounting options - if (options?.global?.mixins) { - for (const mixin of options?.global?.mixins) vm.mixin(mixin) + if (global?.mixins) { + for (const mixin of global.mixins) vm.mixin(mixin) } - if (options?.global?.components) { - for (const key of Object.keys(options?.global?.components)) - vm.component(key, options.global.components[key]) + if (global?.components) { + for (const key of Object.keys(global.components)) + vm.component(key, global.components[key]) } - if (options?.global?.directives) { - for (const key of Object.keys(options?.global?.directives)) - vm.directive(key, options.global.directives[key]) + if (global?.directives) { + for (const key of Object.keys(global.directives)) + vm.directive(key, global.directives[key]) } // provide any values passed via provides mounting option - if (options?.global?.provide) { - for (const key of Reflect.ownKeys(options.global.provide)) { + if (global?.provide) { + for (const key of Reflect.ownKeys(global.provide)) { // @ts-ignore: https://github.com/microsoft/TypeScript/issues/1863 - vm.provide(key, options.global.provide[key]) + vm.provide(key, global.provide[key]) } } // mock globally available properties - if (options?.global?.globalProperties) { - Object.entries(options.global.globalProperties).forEach(([key, value]) => { + if (global?.globalProperties) { + Object.entries(global.globalProperties).forEach(([key, value]) => { vm.config.globalProperties[key] = value }) } diff --git a/src/types.ts b/src/types.ts index d1e8f2cff..66e20ae52 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ +import { Component, ComponentOptions, Directive, Plugin } from 'vue' import { DOMWrapper } from './dom-wrapper' import { ErrorWrapper } from './error-wrapper' @@ -12,3 +13,14 @@ export interface WrapperAPI { text: () => string trigger: (eventString: string) => Promise<(fn?: () => void) => Promise> } + +export type globalMountOptions = { + plugins?: Plugin[] + mixins?: ComponentOptions[] + mocks?: Record + provide?: Record + // TODO how to type `defineComponent`? Using `any` for now. + components?: Record + directives?: Record + globalProperties?: Record +} diff --git a/src/utils.ts b/src/utils.ts index b4a362926..313c462e1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,7 +2,24 @@ import camelCase from 'lodash/camelCase' import upperFirst from 'lodash/upperFirst' import kebabCase from 'lodash/kebabCase' import flow from 'lodash/flow' +import mergeWith from 'lodash/mergeWith' const pascalCase = flow(camelCase, upperFirst) export { kebabCase, pascalCase } + +export function mergeGlobalProperties(configGlobal = {}, mountGlobal = {}) { + return mergeWith({}, configGlobal, mountGlobal, (objValue, srcValue, key) => { + switch (key) { + case 'mocks': + case 'provide': + case 'components': + case 'directives': + case 'globalProperties': + return { ...objValue, ...srcValue } + case 'plugins': + case 'mixins': + return [...(objValue || []), ...(srcValue || [])].filter(Boolean) + } + }) +} diff --git a/tests/config.spec.ts b/tests/config.spec.ts new file mode 100644 index 000000000..5c367f4d6 --- /dev/null +++ b/tests/config.spec.ts @@ -0,0 +1,71 @@ +import { config, mount } from '../src' +import Hello from './components/Hello.vue' + +describe('config', () => { + beforeEach(() => { + config.global = { + components: undefined, + directives: undefined, + mixins: undefined, + plugins: undefined, + globalProperties: undefined, + mocks: undefined, + provide: undefined + } + }) + describe('components', () => { + const Component = { + template: '
{{ msg }}
', + props: ['msg'] + } + + it('allows setting components globally', () => { + config.global.components = { Hello } + const wrapper1 = mount(Component, { props: { msg: 'Wrapper1' } }) + const wrapper2 = mount(Component, { props: { msg: 'Wrapper2' } }) + expect(wrapper1.text()).toEqual('Wrapper1 Hello world') + expect(wrapper2.text()).toEqual('Wrapper2 Hello world') + }) + it('allows overwriting globally set component config on a per mount instance', () => { + config.global.components = { Hello } + const HelloLocal = { template: '
Hello Overwritten
' } + const wrapper1 = mount(Component, { props: { msg: 'Wrapper1' } }) + const wrapper2 = mount(Component, { + props: { msg: 'Wrapper2' }, + global: { components: { Hello: HelloLocal } } + }) + expect(wrapper1.text()).toEqual('Wrapper1 Hello world') + expect(wrapper2.text()).toEqual('Wrapper2 Hello Overwritten') + }) + }) + + describe('directives', () => { + const Directive = { + beforeMount(el: Element) { + el.classList.add('DirectiveAdded') + } + } + const Component = { template: '
msg
' } + + it('allows setting directives globally', () => { + config.global.directives = { Directive } + expect(mount(Component).classes()).toContain('DirectiveAdded') + expect(mount(Component).classes()).toContain('DirectiveAdded') + }) + it('allows overwriting globally set directives', () => { + config.global.directives = { Directive } + const LocalDirective = { + beforeMount(el: Element) { + el.classList.add('LocallyDirectiveAdded') + } + } + + expect(mount(Component).classes()).toContain('DirectiveAdded') + expect( + mount(Component, { + global: { directives: { Directive: LocalDirective } } + }).classes() + ).toContain('LocallyDirectiveAdded') + }) + }) +}) From 327c7108ebf08e5777e678d33612eae90ae1e9d0 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Mon, 13 Apr 2020 11:24:29 +1000 Subject: [PATCH 04/10] refactor: update types and fix broken tests --- src/config.ts | 4 ++-- src/mount.ts | 6 +++--- src/types.ts | 3 ++- src/utils.ts | 6 +++++- tests/config.spec.ts | 3 +++ 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/config.ts b/src/config.ts index 0492584fc..5d20463d5 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,5 +1,5 @@ -import { globalMountOptions } from './types' +import { GlobalMountOptions } from './types' -export const config: { global: globalMountOptions } = { +export const config: { global: GlobalMountOptions } = { global: {} } diff --git a/src/mount.ts b/src/mount.ts index 8ca2156f2..f2b065175 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -8,10 +8,10 @@ import { reactive, ComponentPublicInstance } from 'vue' + import { config } from './config' -import { globalMountOptions } from './types' +import { GlobalMountOptions } from './types' import { mergeGlobalProperties } from './utils' - import { createWrapper, VueWrapper } from './vue-wrapper' import { createEmitMixin } from './emitMixin' import { createDataMixin } from './dataMixin' @@ -27,7 +27,7 @@ interface MountingOptions { default?: Slot [key: string]: Slot } - global?: globalMountOptions + global?: GlobalMountOptions stubs?: Record } diff --git a/src/types.ts b/src/types.ts index 66e20ae52..fc7fad7b7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,5 @@ import { Component, ComponentOptions, Directive, Plugin } from 'vue' + import { DOMWrapper } from './dom-wrapper' import { ErrorWrapper } from './error-wrapper' @@ -14,7 +15,7 @@ export interface WrapperAPI { trigger: (eventString: string) => Promise<(fn?: () => void) => Promise> } -export type globalMountOptions = { +export type GlobalMountOptions = { plugins?: Plugin[] mixins?: ComponentOptions[] mocks?: Record diff --git a/src/utils.ts b/src/utils.ts index 313c462e1..1f7723442 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,12 +3,16 @@ import upperFirst from 'lodash/upperFirst' import kebabCase from 'lodash/kebabCase' import flow from 'lodash/flow' import mergeWith from 'lodash/mergeWith' +import { GlobalMountOptions } from './types' const pascalCase = flow(camelCase, upperFirst) export { kebabCase, pascalCase } -export function mergeGlobalProperties(configGlobal = {}, mountGlobal = {}) { +export function mergeGlobalProperties( + configGlobal = {}, + mountGlobal = {} +): GlobalMountOptions { return mergeWith({}, configGlobal, mountGlobal, (objValue, srcValue, key) => { switch (key) { case 'mocks': diff --git a/tests/config.spec.ts b/tests/config.spec.ts index 5c367f4d6..cd73c57b0 100644 --- a/tests/config.spec.ts +++ b/tests/config.spec.ts @@ -13,6 +13,7 @@ describe('config', () => { provide: undefined } }) + describe('components', () => { const Component = { template: '
{{ msg }}
', @@ -26,6 +27,7 @@ describe('config', () => { expect(wrapper1.text()).toEqual('Wrapper1 Hello world') expect(wrapper2.text()).toEqual('Wrapper2 Hello world') }) + it('allows overwriting globally set component config on a per mount instance', () => { config.global.components = { Hello } const HelloLocal = { template: '
Hello Overwritten
' } @@ -52,6 +54,7 @@ describe('config', () => { expect(mount(Component).classes()).toContain('DirectiveAdded') expect(mount(Component).classes()).toContain('DirectiveAdded') }) + it('allows overwriting globally set directives', () => { config.global.directives = { Directive } const LocalDirective = { From f84e87ce3ae5513958fb817f404dc75cd09ad6b5 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Mon, 13 Apr 2020 12:11:02 +1000 Subject: [PATCH 05/10] refactor: update rollup build --- package.json | 3 --- rollup.config.js | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 482130145..cbf109568 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,5 @@ "*.ts": [ "prettier --parser=typescript --write" ] - }, - "dependencies": { - "lodash": "^4.17.15" } } diff --git a/rollup.config.js b/rollup.config.js index d3a65ae96..741fc2206 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -21,7 +21,7 @@ function createEntry(options) { const config = { input, external: [ - 'vue', + 'vue', 'lodash/mergeWith', 'lodash/camelCase', 'lodash/upperFirst', @@ -37,7 +37,7 @@ function createEntry(options) { } if (format === 'es') { - config.output.file = isBrowser ? pkg.browser : pkg.module + config.output.file = isBrowser ? pkg.browser : pkg.module } if (format === 'cjs') { config.output.file = pkg.main From e1b8a2bcc49ca89d59532389247c54ae06ecfd32 Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Mon, 13 Apr 2020 23:29:50 +0300 Subject: [PATCH 06/10] tests: add mocks tests --- tests/config.spec.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/config.spec.ts b/tests/config.spec.ts index cd73c57b0..23283899a 100644 --- a/tests/config.spec.ts +++ b/tests/config.spec.ts @@ -71,4 +71,27 @@ describe('config', () => { ).toContain('LocallyDirectiveAdded') }) }) + + describe('mocks', () => { + it('sets mock everywhere', () => { + config.global.mocks = { + foo: 'bar' + } + const Component = { template: '
{{ foo }}
' } + expect(mount(Component).text()).toEqual('bar') + expect(mount(Component).text()).toEqual('bar') + }) + + it('allows overwriting a global mock', () => { + config.global.mocks = { + foo: 'bar' + } + const Component = { template: '
{{ foo }}
' } + + expect(mount(Component).text()).toEqual('bar') + expect( + mount(Component, { global: { mocks: { foo: 'baz' } } }).text() + ).toEqual('baz') + }) + }) }) From 9d2805a991f6c1a7e57786565a287da2cd6adead Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Thu, 16 Apr 2020 22:32:29 +0300 Subject: [PATCH 07/10] fix: fix missing type --- src/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types.ts b/src/types.ts index fc7fad7b7..201ed8f9b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -24,4 +24,5 @@ export type GlobalMountOptions = { components?: Record directives?: Record globalProperties?: Record + stubs?: Record } From 2ec6d1704ecf7d25495975e002880f9fa8714ecf Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Thu, 16 Apr 2020 22:35:09 +0300 Subject: [PATCH 08/10] chore: remove globalProperties --- src/mount.ts | 7 ------- src/types.ts | 2 -- tests/config.spec.ts | 1 - .../mountingOptions/globalProperties.spec.ts | 20 ------------------- 4 files changed, 30 deletions(-) delete mode 100644 tests/mountingOptions/globalProperties.spec.ts diff --git a/src/mount.ts b/src/mount.ts index f2b065175..fbc6e25ad 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -136,13 +136,6 @@ export function mount( } } - // mock globally available properties - if (global?.globalProperties) { - Object.entries(global.globalProperties).forEach(([key, value]) => { - vm.config.globalProperties[key] = value - }) - } - // add tracking for emitted events const { emitMixin, events } = createEmitMixin() vm.mixin(emitMixin) diff --git a/src/types.ts b/src/types.ts index 201ed8f9b..afb4dd40a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,9 +20,7 @@ export type GlobalMountOptions = { mixins?: ComponentOptions[] mocks?: Record provide?: Record - // TODO how to type `defineComponent`? Using `any` for now. components?: Record directives?: Record - globalProperties?: Record stubs?: Record } diff --git a/tests/config.spec.ts b/tests/config.spec.ts index 23283899a..c1d1fa417 100644 --- a/tests/config.spec.ts +++ b/tests/config.spec.ts @@ -8,7 +8,6 @@ describe('config', () => { directives: undefined, mixins: undefined, plugins: undefined, - globalProperties: undefined, mocks: undefined, provide: undefined } diff --git a/tests/mountingOptions/globalProperties.spec.ts b/tests/mountingOptions/globalProperties.spec.ts deleted file mode 100644 index 2754bac75..000000000 --- a/tests/mountingOptions/globalProperties.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { h } from 'vue' -import { mount } from '../../src' - -describe('globalProperties', () => { - it('adds globally available properties to the component', () => { - const Component = { - render() { - return h('div', this.foo) - } - } - const wrapper = mount(Component, { - global: { - globalProperties: { - foo: 'bar' - } - } - }) - expect(wrapper.html()).toEqual('
bar
') - }) -}) From 0590a4c2e381342db80d599042165a5a8f7bd060 Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Sat, 18 Apr 2020 17:24:29 +0300 Subject: [PATCH 09/10] chore: remove left over stubs --- src/mount.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mount.ts b/src/mount.ts index b90ba753d..8af8409f1 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -28,7 +28,6 @@ interface MountingOptions { [key: string]: Slot } global?: GlobalMountOptions - stubs?: Record } export function mount( From 4ab15cde46e88a897aa0c80d59f001387a53827b Mon Sep 17 00:00:00 2001 From: dobromir-hristov Date: Sat, 18 Apr 2020 17:32:34 +0300 Subject: [PATCH 10/10] chore: merge conflicts --- src/mount.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mount.ts b/src/mount.ts index 8af8409f1..da428cb24 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -6,7 +6,8 @@ import { VNodeNormalizedChildren, transformVNodeArgs, reactive, - ComponentPublicInstance + ComponentPublicInstance, + Component } from 'vue' import { config } from './config'