Skip to content

test: test for provide/inject #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 5, 2021
Merged
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
258 changes: 258 additions & 0 deletions test/v3/runtime-core/apiInject.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
import {
h,
provide,
inject,
InjectionKey,
ref,
nextTick,
Ref,
reactive,
defineComponent,
createApp,
} from '../../../src'
import { mockWarn } from '../../helpers'

describe('api: provide/inject', () => {
mockWarn(true)
it('string keys', async () => {
const Provider = {
setup() {
provide('foo', 1)
return () => h(Middle)
},
}

const Middle = {
setup() {
return () => h(Consumer)
},
}

const Consumer = {
setup() {
const foo = inject<number>('foo')
return () => h('div', foo as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>1</div>`)
})

it('symbol keys', () => {
// also verifies InjectionKey type sync
const key: InjectionKey<number> = Symbol()

const Provider = {
setup() {
provide(key, 1)
return () => h(Middle)
},
}

const Middle = {
setup() {
return () => h(Consumer)
},
}

const Consumer = {
setup() {
const foo = inject(key) || 1
return () => h('div', (foo + 1) as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>2</div>`)
})

it('default values', () => {
const Provider = {
setup() {
provide('foo', 'foo')
return () => h(Middle)
},
}

const Middle = {
setup() {
return () => h(Consumer)
},
}

const Consumer = {
setup() {
// default value should be ignored if value is provided
const foo = inject('foo', 'fooDefault')
// default value should be used if value is not provided
const bar = inject('bar', 'bar')
return () => h('div', (foo + bar) as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>foobar</div>`)
})

it('bound to instance', () => {
const Provider = {
setup() {
return () => h(Consumer)
},
}

const Consumer = defineComponent({
name: 'Consumer',
inject: {
foo: {
from: 'foo',
default() {
return this!.$options.name
},
},
},
render() {
return h('div', this.foo as unknown as string)
},
})

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>Consumer</div>`)
})

it('nested providers', () => {
const ProviderOne = {
setup() {
provide('foo', 'foo')
provide('bar', 'bar')
return () => h(ProviderTwo)
},
}

const ProviderTwo = {
setup() {
// override parent value
provide('foo', 'fooOverride')
provide('baz', 'baz')
return () => h(Consumer)
},
}

const Consumer = {
setup() {
const foo = inject('foo')
const bar = inject('bar')
const baz = inject('baz')
return () => h('div', [foo, bar, baz].join(',') as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(ProviderOne).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>fooOverride,bar,baz</div>`)
})

it('reactivity with refs', async () => {
const count = ref(1)

const Provider = {
setup() {
provide('count', count)
return () => h(Middle)
},
}

const Middle = {
setup() {
return () => h(Consumer)
},
}

const Consumer = {
setup() {
const count = inject<Ref<number>>('count')!
return () => h('div', count.value as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>1</div>`)

count.value++
await nextTick()
expect(vm.$el.outerHTML).toBe(`<div>2</div>`)
})

it('reactivity with objects', async () => {
const rootState = reactive({ count: 1 })

const Provider = {
setup() {
provide('state', rootState)
return () => h(Middle)
},
}

const Middle = {
setup() {
return () => h(Consumer)
},
}

const Consumer = {
setup() {
const state = inject<typeof rootState>('state')!
return () => h('div', state.count as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>1</div>`)

rootState.count++
await nextTick()
expect(vm.$el.outerHTML).toBe(`<div>2</div>`)
})

it('should warn unfound', () => {
const Provider = {
setup() {
return () => h(Consumer)
},
}

const Consumer = {
setup() {
const foo = inject('foo')
expect(foo).toBeUndefined()
return () => h('div', foo as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Provider).mount(root)
expect(vm.$el.outerHTML).toBe(`<div></div>`)
expect(`[Vue warn]: Injection "foo" not found`).toHaveBeenWarned()
})

it('should not self-inject', () => {
const Comp = {
setup() {
provide('foo', 'foo')
const injection = inject('foo', null)
return () => h('div', injection as unknown as string)
},
}

const root = document.createElement('div')
const vm = createApp(Comp).mount(root)
expect(vm.$el.outerHTML).toBe(`<div>foo</div>`)
})
})