diff --git a/src/mount.ts b/src/mount.ts index 086653152..03b5b4617 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -136,7 +136,6 @@ export function mount( // create the app const app = createApp(Parent) - const global = mergeGlobalProperties(config.global, options?.global) // global mocks mixin @@ -152,6 +151,13 @@ export function mount( app.mixin(mixin) } + // AppConfig + if (global?.config) { + for (const [k, v] of Object.entries(global.config)) { + app.config[k] = v + } + } + // use and plugins from mounting options if (global?.plugins) { for (const use of global.plugins) app.use(use) diff --git a/src/types.ts b/src/types.ts index 5b31d4a94..c0c3c83d2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { Component, ComponentOptions, Directive, Plugin } from 'vue' +import { Component, ComponentOptions, Directive, Plugin, AppConfig } from 'vue' interface RefSelector { ref: string @@ -21,6 +21,7 @@ export type FindAllComponentsSelector = NameSelector | string export type GlobalMountOptions = { plugins?: Plugin[] + config?: AppConfig mixins?: ComponentOptions[] mocks?: Record provide?: Record diff --git a/tests/components/AsyncComponent.vue b/tests/components/AsyncComponent.vue new file mode 100644 index 000000000..e69de29bb diff --git a/tests/features/async-components.spec.ts b/tests/features/async-components.spec.ts new file mode 100644 index 000000000..e829668a5 --- /dev/null +++ b/tests/features/async-components.spec.ts @@ -0,0 +1,114 @@ +import { defineAsyncComponent, defineComponent, h, AppConfig } from 'vue' +import flushPromises from 'flush-promises' + +import { mount } from '../../src' + +const config: AppConfig = { + devtools: false, + optionMergeStrategies: {}, + globalProperties: {}, + isCustomElement: (tag: string) => false, + performance: false, + errorHandler: (error: Error) => { + if (error.message.match(/Async component failed to load./)) { + return + } + throw error + } +} + +// AsyncComponents are documented here: https://github.com/vuejs/rfcs/blob/async-component/active-rfcs/0026-async-component-api.md +describe('defineAsyncComponent', () => { + beforeAll(jest.useFakeTimers) + afterAll(jest.useRealTimers) + + it('works with the basic usage', async () => { + const AsyncHello = defineAsyncComponent(() => + import('../components/Hello.vue') + ) + const Comp = defineComponent({ + render() { + return h('div', [h(AsyncHello)]) + } + }) + + const wrapper = mount(Comp, { global: { config } }) + await flushPromises() + expect(wrapper.html()).toContain('Hello world') + }) + + it('works with options usage', async () => { + const Async = defineAsyncComponent({ + loader: () => + new Promise((res) => { + setTimeout(() => { + res({ + template: '
Async Component
' + }) + }, 75) + }), + loadingComponent: { + template: '
Loading Component
' + }, + delay: 10 + }) + + const Comp = defineComponent({ + render() { + return h('div', [h(Async)]) + } + }) + + const wrapper = mount(Comp, { global: { config } }) + jest.runTimersToTime(35) + await flushPromises() + expect(wrapper.html()).toContain('Loading Component') + + jest.runTimersToTime(100) + await flushPromises() + expect(wrapper.html()).toContain('Async Component') + }) + + it('catches error and renders ErrorComponent', async () => { + const Async = defineAsyncComponent({ + loader: () => + new Promise((res, rej) => { + rej('Async component failed to load.') + }), + errorComponent: { + template: '
Error Component
' + }, + onError(error, retry, fail, attempts) { + fail() + } + }) + + const Comp = defineComponent({ + render() { + return h('div', [h(Async)]) + } + }) + + const wrapper = mount(Comp, { global: { config } }) + await flushPromises() + + expect(wrapper.html()).toContain('Error Component') + }) + + // TODO: Find out why this does not work + // Is it valid to have an AsyncComponent as the root? Was it ever? + it.skip('works when AsyncComponent is the root', async () => { + const AsyncHello = defineAsyncComponent(() => + import('../components/Hello.vue') + ) + const Comp = defineComponent({ + render() { + return h(AsyncHello) + } + }) + + const wrapper = mount(Comp, { global: { config } }) + await flushPromises() + expect(wrapper.html()).toContain('Hello world') + }) +})