Skip to content
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
8 changes: 7 additions & 1 deletion src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ export function mount(

// create the app
const app = createApp(Parent)

const global = mergeGlobalProperties(config.global, options?.global)

// global mocks mixin
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, ComponentOptions, Directive, Plugin } from 'vue'
import { Component, ComponentOptions, Directive, Plugin, AppConfig } from 'vue'

interface RefSelector {
ref: string
Expand All @@ -21,6 +21,7 @@ export type FindAllComponentsSelector = NameSelector | string

export type GlobalMountOptions = {
plugins?: Plugin[]
config?: AppConfig
mixins?: ComponentOptions[]
mocks?: Record<string, any>
provide?: Record<any, any>
Expand Down
Empty file.
114 changes: 114 additions & 0 deletions tests/features/async-components.spec.ts
Original file line number Diff line number Diff line change
@@ -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<any>((res) => {
setTimeout(() => {
res({
template: '<div>Async Component</div>'
})
}, 75)
}),
loadingComponent: {
template: '<div>Loading Component</div>'
},
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<any>((res, rej) => {
rej('Async component failed to load.')
}),
errorComponent: {
template: '<div>Error Component</div>'
},
onError(error, retry, fail, attempts) {
fail()
}
Comment on lines +81 to +83
Copy link
Member

@afontcu afontcu May 2, 2020

Choose a reason for hiding this comment

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

I think this onError is a bit redundant? The option is used to have some retry control, but here we're just failing no matter what.

Suggested change
onError(error, retry, fail, attempts) {
fail()
}

Copy link
Member

Choose a reason for hiding this comment

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

Hm, also the test is passing but it yields some warns and errors:

image

Copy link
Member

Choose a reason for hiding this comment

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

Not sure if these error logs are somewhat expected, and we should just mock console for the test and call it a day… 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

I had this thought too. Some other tests also throw and error. Is there any benefit to mocking the console? If printing the error is correct, I don't keep it.

Copy link
Member

Choose a reason for hiding this comment

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

I tend to mute them to make it the output cleaner in the long run, but I don't care much either. Unless the console error is part of the expected output, then I spy it and assert the times called and so.

Copy link
Member

Choose a reason for hiding this comment

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

(I still believe the onError bit can be removed)

Copy link
Contributor

Choose a reason for hiding this comment

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

We can have our own Vue errorHandler, to easily assert on it without mocking console.error

Copy link
Member Author

Choose a reason for hiding this comment

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

I will make this change, thanks

})

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')
})
})