Skip to content

Commit a695025

Browse files
committed
fix(runtime-utils): reject promise on error render + mount helpers
1 parent 79f1e14 commit a695025

File tree

5 files changed

+645
-6
lines changed

5 files changed

+645
-6
lines changed
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
3+
import { Suspense } from 'vue'
4+
import { mount } from '@vue/test-utils'
5+
import { mountSuspended } from '@nuxt/test-utils/runtime'
6+
import { NuxtErrorBoundary } from '#components'
7+
8+
describe('mountSuspended handle error', () => {
9+
describe('vue/test-utils compatibility', () => {
10+
it('throws on mounted', async () => {
11+
const TestComponent = defineComponent({
12+
template: '<div></div>',
13+
mounted() {
14+
throw new Error('thrown')
15+
},
16+
})
17+
18+
expect(() => mount(TestComponent)).toThrow('thrown')
19+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
20+
})
21+
22+
it('child throws on mounted', async () => {
23+
const ChildComponent = defineComponent({
24+
template: '<div></div>',
25+
mounted() {
26+
throw new Error('thrown')
27+
},
28+
})
29+
30+
const TestComponent = defineComponent({
31+
render() {
32+
return h('div', [h(ChildComponent)])
33+
},
34+
})
35+
36+
expect(() => mount(TestComponent)).toThrow('thrown')
37+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
38+
})
39+
40+
it('throws on setup', async () => {
41+
const TestComponent = defineComponent({
42+
template: '<div></div>',
43+
setup() {
44+
throw new Error('thrown')
45+
},
46+
})
47+
48+
expect(() => mount(TestComponent)).toThrow('thrown')
49+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
50+
})
51+
52+
it('child throws on setup', async () => {
53+
const ChildComponent = defineComponent({
54+
template: '<div></div>',
55+
setup() {
56+
throw new Error('thrown')
57+
},
58+
})
59+
60+
const TestComponent = defineComponent({
61+
render() {
62+
return h('div', [h(ChildComponent)])
63+
},
64+
})
65+
66+
expect(() => mount(TestComponent)).toThrow('thrown')
67+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
68+
})
69+
70+
it('onErrorCaptured throws on setup', async () => {
71+
const TestComponent = defineComponent({
72+
template: '<div></div>',
73+
setup() {
74+
onErrorCaptured(() => false)
75+
throw new Error('thrown')
76+
},
77+
})
78+
79+
expect(() => mount(TestComponent)).toThrow('thrown')
80+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
81+
})
82+
83+
it('onErrorCaptured child throws on setup', async () => {
84+
const ChildComponent = defineComponent({
85+
template: '<div>hello</div>',
86+
setup() {
87+
throw new Error('thrown')
88+
},
89+
})
90+
91+
const TestComponent = defineComponent({
92+
setup() {
93+
onErrorCaptured(() => false)
94+
},
95+
render() {
96+
return h('div', [h(ChildComponent)])
97+
},
98+
})
99+
100+
const vWrapper = mount(TestComponent)
101+
const nWrapper = await mountSuspended(TestComponent)
102+
103+
expect(nWrapper.text()).toBe(vWrapper.text())
104+
})
105+
106+
it('global errorHandler handle throws on setup', async () => {
107+
const TestComponent = defineComponent({
108+
template: '<div></div>',
109+
setup() {
110+
throw 'thrown'
111+
},
112+
})
113+
114+
const errorHandler = vi.fn()
115+
116+
expect(
117+
() => mount(TestComponent, { global: { config: { errorHandler } } }),
118+
).toThrow('thrown')
119+
expect(errorHandler).toHaveBeenNthCalledWith(1, 'thrown', expect.anything(), expect.anything())
120+
121+
await expect(
122+
() => mountSuspended(TestComponent, { global: { config: { errorHandler } } }),
123+
).rejects.toThrow('thrown')
124+
expect(errorHandler).toHaveBeenNthCalledWith(2, 'thrown', expect.anything(), expect.anything())
125+
})
126+
127+
it('global errorHandler throws', async () => {
128+
const TestComponent = defineComponent({
129+
template: '<div></div>',
130+
setup() {
131+
throw 'thrown'
132+
},
133+
})
134+
135+
const errorHandler = () => {
136+
throw 'error global errorHandler'
137+
}
138+
139+
expect(
140+
() => mount(TestComponent, { global: { config: { errorHandler } } }),
141+
).toThrow('error global errorHandler')
142+
143+
await expect(
144+
() => mountSuspended(TestComponent, { global: { config: { errorHandler } } }),
145+
).rejects.toThrow('error global errorHandler')
146+
})
147+
148+
it('global errorHandler handle throws on after mounted ', async () => {
149+
const TestComponent = defineComponent({
150+
setup() {
151+
const onClick = () => {
152+
throw 'thrown'
153+
}
154+
return () => h('button', { onClick })
155+
},
156+
})
157+
158+
const errorHandler = vi.fn()
159+
160+
const vWrapper = mount(TestComponent, { global: { config: { errorHandler } } })
161+
await vWrapper.find('button').trigger('click')
162+
expect(errorHandler).toHaveBeenNthCalledWith(1, 'thrown', expect.anything(), expect.anything())
163+
164+
const nWrapper = await mountSuspended(TestComponent, { global: { config: { errorHandler } } })
165+
await nWrapper.find('button').trigger('click')
166+
expect(errorHandler).toHaveBeenNthCalledWith(2, 'thrown', expect.anything(), expect.anything())
167+
})
168+
})
169+
170+
describe('nuxt/test-utils', () => {
171+
it('throws on async setup', async () => {
172+
const TestComponent = defineComponent({
173+
template: '<div></div>',
174+
async setup() {
175+
throw new Error('thrown')
176+
},
177+
})
178+
179+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
180+
})
181+
182+
it('child throws on async setup', async () => {
183+
const ChildComponent = defineComponent({
184+
template: '<div></div>',
185+
async setup() {
186+
throw new Error('thrown')
187+
},
188+
})
189+
190+
const TestComponent = defineComponent({
191+
render() {
192+
return h('div', [h(ChildComponent)])
193+
},
194+
})
195+
196+
await expect(() => mountSuspended(TestComponent)).rejects.toThrow('thrown')
197+
})
198+
199+
it('onErrorCaptured child throws on async setup', async () => {
200+
const ChildComponent = defineComponent({
201+
template: '<div>hello</div>',
202+
async setup() {
203+
throw new Error('thrown')
204+
},
205+
})
206+
207+
const TestComponent = defineComponent({
208+
setup() {
209+
onErrorCaptured(() => false)
210+
},
211+
render() {
212+
return h('div', [h(ChildComponent)])
213+
},
214+
})
215+
216+
expect((await mountSuspended(TestComponent)).text()).toBe('hello')
217+
})
218+
219+
it('global errorHandler handle throws on async setup', async () => {
220+
const TestComponent = defineComponent({
221+
template: '<div></div>',
222+
async setup() {
223+
throw 'thrown'
224+
},
225+
})
226+
227+
const errorHandler = vi.fn()
228+
229+
await expect(
230+
() => mountSuspended(TestComponent, { global: { config: { errorHandler } } }),
231+
).rejects.toThrow('thrown')
232+
expect(errorHandler).toHaveBeenNthCalledWith(1, 'thrown', expect.anything(), expect.anything())
233+
})
234+
235+
it('global errorHandler handle throws on after async setup ', async () => {
236+
const TestComponent = defineComponent({
237+
async setup() {
238+
const onClick = () => {
239+
throw 'thrown'
240+
}
241+
return () => h('button', { onClick })
242+
},
243+
})
244+
245+
const errorHandler = vi.fn()
246+
247+
const nWrapper = await mountSuspended(TestComponent, { global: { config: { errorHandler } } })
248+
await nWrapper.find('button').trigger('click')
249+
expect(errorHandler).toHaveBeenNthCalledWith(1, 'thrown', expect.anything(), expect.anything())
250+
})
251+
252+
it('NuxtErrorBoundary handle throws on setup', async () => {
253+
const ChildComponent = defineComponent({
254+
template: '<div></div>',
255+
setup() {
256+
throw createError({ message: 'thrown', fatal: true })
257+
},
258+
})
259+
260+
const TestComponent = defineComponent({
261+
render() {
262+
return h(NuxtErrorBoundary, null, {
263+
default: () => h(ChildComponent),
264+
error: () => h('div', 'error'),
265+
})
266+
},
267+
})
268+
269+
expect((await mountSuspended(TestComponent)).text()).toBe('error')
270+
})
271+
272+
it('NuxtErrorBoundary/Suspense wrappedInstance throws on async setup', async () => {
273+
const ChildComponent = defineComponent({
274+
template: '<div></div>',
275+
async setup() {
276+
throw createError({ message: 'thrown', fatal: true })
277+
},
278+
})
279+
280+
const TestComponent = defineComponent({
281+
render() {
282+
return h(NuxtErrorBoundary, null, {
283+
default: () => h(Suspense, [h(ChildComponent)]),
284+
error: () => h('div', 'error'),
285+
})
286+
},
287+
})
288+
289+
expect((await mountSuspended(TestComponent)).text()).toBe('error')
290+
})
291+
})
292+
})

0 commit comments

Comments
 (0)