]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: test for provide/inject
authorEvan You <yyx990803@gmail.com>
Mon, 26 Aug 2019 20:14:23 +0000 (16:14 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 26 Aug 2019 20:14:23 +0000 (16:14 -0400)
packages/runtime-core/__tests__/apiInject.spec.ts

index a11163a6611f6085e4464ef50e730de48cb47168..a5d09a4ff7e3d7fe8750e2e82bd76ef398ebdf03 100644 (file)
@@ -1,5 +1,261 @@
+import {
+  h,
+  provide,
+  inject,
+  InjectionKey,
+  ref,
+  nextTick,
+  Ref,
+  readonly,
+  reactive
+} from '../src/index'
+import { render, nodeOps, serialize, mockWarn } from '@vue/runtime-test'
+
 // reference: https://vue-composition-api-rfc.netlify.com/api.html#provide-inject
 
 describe('api: provide/inject', () => {
-  test.todo('should work')
+  mockWarn()
+
+  it('string keys', () => {
+    const Provider = {
+      setup() {
+        provide('foo', 1)
+        return () => h(Middle)
+      }
+    }
+
+    const Middle = {
+      render: () => h(Consumer)
+    }
+
+    const Consumer = {
+      setup() {
+        const foo = inject('foo')
+        return () => foo
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).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 = {
+      render: () => h(Consumer)
+    }
+
+    const Consumer = {
+      setup() {
+        const foo = inject(key) || 1
+        return () => foo + 1
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).toBe(`<div>2</div>`)
+  })
+
+  it('default values', () => {
+    const Provider = {
+      setup() {
+        provide('foo', 'foo')
+        return () => h(Middle)
+      }
+    }
+
+    const Middle = {
+      render: () => 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 () => foo + bar
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).toBe(`<div>foobar</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 () => [foo, bar, baz].join(',')
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(ProviderOne), root)
+    expect(serialize(root)).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 = {
+      render: () => h(Consumer)
+    }
+
+    const Consumer = {
+      setup() {
+        const count = inject('count') as Ref<number>
+        return () => count.value
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).toBe(`<div>1</div>`)
+
+    count.value++
+    await nextTick()
+    expect(serialize(root)).toBe(`<div>2</div>`)
+  })
+
+  it('reactivity with readonly refs', async () => {
+    const count = ref(1)
+
+    const Provider = {
+      setup() {
+        provide('count', readonly(count))
+        return () => h(Middle)
+      }
+    }
+
+    const Middle = {
+      render: () => h(Consumer)
+    }
+
+    const Consumer = {
+      setup() {
+        const count = inject('count') as Ref<number>
+        // should not work
+        count.value++
+        return () => count.value
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).toBe(`<div>1</div>`)
+
+    expect(
+      `Set operation on key "value" failed: target is readonly`
+    ).toHaveBeenWarned()
+
+    // source mutation should still work
+    count.value++
+    await nextTick()
+    expect(serialize(root)).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 = {
+      render: () => h(Consumer)
+    }
+
+    const Consumer = {
+      setup() {
+        const state = inject('state') as typeof rootState
+        return () => state.count
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).toBe(`<div>1</div>`)
+
+    rootState.count++
+    await nextTick()
+    expect(serialize(root)).toBe(`<div>2</div>`)
+  })
+
+  it('reactivity with readonly objects', async () => {
+    const rootState = reactive({ count: 1 })
+
+    const Provider = {
+      setup() {
+        provide('state', readonly(rootState))
+        return () => h(Middle)
+      }
+    }
+
+    const Middle = {
+      render: () => h(Consumer)
+    }
+
+    const Consumer = {
+      setup() {
+        const state = inject('state') as typeof rootState
+        // should not work
+        state.count++
+        return () => state.count
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Provider), root)
+    expect(serialize(root)).toBe(`<div>1</div>`)
+
+    expect(
+      `Set operation on key "count" failed: target is readonly`
+    ).toHaveBeenWarned()
+
+    rootState.count++
+    await nextTick()
+    expect(serialize(root)).toBe(`<div>2</div>`)
+  })
 })