Skip to content

Commit 64baaf6

Browse files
test(apiInject): add unit tests for Dependency Injection Inheritance bug
1 parent 707a9c7 commit 64baaf6

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

packages/runtime-core/__tests__/apiInject.spec.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
hasInjectionContext,
77
inject,
88
nextTick,
9+
onBeforeUpdate,
10+
onMounted,
911
provide,
1012
reactive,
1113
readonly,
@@ -347,6 +349,104 @@ describe('api: provide/inject', () => {
347349
expect(serialize(root)).toBe(`<div><!----></div>`)
348350
})
349351

352+
// #13921
353+
it('overlapping inheritance cycles', async () => {
354+
let shouldProvide = ref(false)
355+
356+
const Comp4 = {
357+
props: ['data'],
358+
setup() {
359+
const data = ref('foo -1')
360+
361+
onMounted(() => {
362+
data.value = inject('foo', 'foo 0')
363+
})
364+
365+
onBeforeUpdate(() => {
366+
data.value = inject('foo', 'foo 0')
367+
})
368+
369+
return () => [h('div', data.value)]
370+
},
371+
}
372+
373+
const Comp3 = {
374+
props: ['data'],
375+
setup() {
376+
const data = ref('foo -1')
377+
378+
onMounted(() => {
379+
data.value = inject('foo', 'foo 0')
380+
})
381+
382+
onBeforeUpdate(() => {
383+
data.value = inject('foo', 'foo 0')
384+
})
385+
386+
return () => [
387+
h('div', data.value),
388+
h(Comp4, { data: shouldProvide.value }),
389+
]
390+
},
391+
}
392+
393+
const Comp2 = {
394+
setup() {
395+
const data = ref('foo -1')
396+
397+
onMounted(() => {
398+
data.value = inject('foo', 'foo 0')
399+
})
400+
401+
onBeforeUpdate(() => {
402+
if (shouldProvide.value) {
403+
provide('foo', 'foo 2')
404+
}
405+
406+
data.value = inject('foo', 'foo 0')
407+
})
408+
409+
return () => [
410+
h('div', data.value),
411+
h(Comp3, { data: shouldProvide.value }),
412+
]
413+
},
414+
}
415+
416+
const Comp1 = {
417+
setup() {
418+
provide('foo', 'foo 1')
419+
const data = ref('foo -1')
420+
421+
onMounted(() => {
422+
data.value = inject('foo', 'foo 0')
423+
})
424+
425+
onBeforeUpdate(() => {
426+
data.value = inject('foo', 'foo 0')
427+
})
428+
429+
return () => [h('div', data.value), h(Comp2)]
430+
},
431+
}
432+
433+
const root = nodeOps.createElement('div')
434+
render(h(Comp1), root)
435+
436+
shouldProvide.value = true
437+
await nextTick()
438+
439+
/*
440+
First (Root Component) should be "foo 0" because it is the Root Component and provdes shall only be injected to Descandents.
441+
Second (Component 2) should be "foo 1" because it should inherit the provide from the Root Component
442+
Third (Component 3) should be "foo 2" because it should inherit the provide from Component 2 (in the second render when shouldProvide = true)
443+
Fourth (Component 4) should also be "foo 2" because it should inherit the provide from Component 3 which should inherit it from Component 2 (in the second render when shouldProvide = true)
444+
*/
445+
expect(serialize(root)).toBe(
446+
`<div><div>foo 0</div><div>foo 1</div><div>foo 2</div><div>foo 2</div></div>`,
447+
)
448+
})
449+
350450
describe('hasInjectionContext', () => {
351451
it('should be false outside of setup', () => {
352452
expect(hasInjectionContext()).toBe(false)

0 commit comments

Comments
 (0)