From 417ab389a223804b44b3deb38036510401739b71 Mon Sep 17 00:00:00 2001 From: Bodo Graumann Date: Mon, 6 Dec 2021 16:10:38 +0100 Subject: [PATCH 1/3] feat: expose providePinia to use multiple root stores --- .../pinia/__tests__/multipleRoots.spec.ts | 98 +++++++++++++++++++ packages/pinia/src/index.ts | 2 +- packages/pinia/src/rootStore.ts | 8 ++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 packages/pinia/__tests__/multipleRoots.spec.ts diff --git a/packages/pinia/__tests__/multipleRoots.spec.ts b/packages/pinia/__tests__/multipleRoots.spec.ts new file mode 100644 index 0000000000..3efdcfe6ef --- /dev/null +++ b/packages/pinia/__tests__/multipleRoots.spec.ts @@ -0,0 +1,98 @@ +import { createPinia, defineStore, providePinia } from '../src' +import { mount } from '@vue/test-utils' +import { defineComponent } from 'vue' + +describe('Multiple Roots', () => { + function defineMyStore() { + return defineStore({ + id: 'main', + state: () => ({ + n: 0, + }), + }) + } + + it('uses the same root in child components by default', () => { + expect.assertions(2) + const pinia = createPinia() + const useStore = defineMyStore() + + const ChildComponent = defineComponent({ + template: 'no', + setup() { + const store = useStore() + expect(store.n).toBe(1) + }, + }) + + mount( + { + template: '', + components: { ChildComponent }, + setup() { + const store = useStore() + expect(store.n).toBe(0) + store.n++ + }, + }, + { global: { plugins: [pinia] } } + ) + }) + + it('can use a new pinia root for all child components', async () => { + expect.assertions(2) + const pinia = createPinia() + const useStore = defineMyStore() + + const ChildComponent = defineComponent({ + template: 'no', + setup() { + const store = useStore() + expect(store.n).toBe(0) + }, + }) + mount( + { + template: '', + components: { ChildComponent }, + setup() { + providePinia(createPinia()) + const store = useStore() + expect(store.n).toBe(0) + store.n++ + }, + }, + { global: { plugins: [pinia] } } + ) + }) + + it('state is shared between child components', async () => { + expect.assertions(3) + const pinia = createPinia() + const useStore = defineMyStore() + + const ChildComponent = defineComponent({ + template: 'no', + props: { counter: { type: Number, required: true } }, + setup(props: { counter: number }) { + const store = useStore() + expect(store.n).toBe(props.counter) + store.n++ + }, + }) + mount( + { + template: + '', + components: { ChildComponent }, + setup() { + const store = useStore() + expect(store.n).toBe(0) + store.n++ + providePinia(createPinia()) + }, + }, + { global: { plugins: [pinia] } } + ) + }) +}) diff --git a/packages/pinia/src/index.ts b/packages/pinia/src/index.ts index 9735ef3767..3cb17772ce 100644 --- a/packages/pinia/src/index.ts +++ b/packages/pinia/src/index.ts @@ -1,7 +1,7 @@ /** * @module pinia */ -export { setActivePinia, getActivePinia } from './rootStore' +export { setActivePinia, getActivePinia, providePinia } from './rootStore' export { createPinia } from './createPinia' export type { Pinia, diff --git a/packages/pinia/src/rootStore.ts b/packages/pinia/src/rootStore.ts index 833566dd18..4bdf81777f 100644 --- a/packages/pinia/src/rootStore.ts +++ b/packages/pinia/src/rootStore.ts @@ -4,6 +4,7 @@ import { getCurrentInstance, inject, InjectionKey, + provide, Ref, } from 'vue-demi' import { @@ -97,6 +98,13 @@ export const piniaSymbol = ( __DEV__ ? Symbol('pinia') : /* istanbul ignore next */ Symbol() ) as InjectionKey +/** + * Define which pinia to use in all child components. + */ +export function providePinia(pinia: Pinia) { + provide(piniaSymbol, pinia) +} + /** * Context argument passed to Pinia plugins. */ From ef7b29c185cd3d971824a5c66e3b7289f75b13e9 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 18 Feb 2022 23:57:36 +0100 Subject: [PATCH 2/3] test: refactor --- .../pinia/__tests__/multipleRoots.spec.ts | 39 +++---------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/packages/pinia/__tests__/multipleRoots.spec.ts b/packages/pinia/__tests__/multipleRoots.spec.ts index 3efdcfe6ef..bfd318301f 100644 --- a/packages/pinia/__tests__/multipleRoots.spec.ts +++ b/packages/pinia/__tests__/multipleRoots.spec.ts @@ -4,8 +4,7 @@ import { defineComponent } from 'vue' describe('Multiple Roots', () => { function defineMyStore() { - return defineStore({ - id: 'main', + return defineStore('main', { state: () => ({ n: 0, }), @@ -13,7 +12,6 @@ describe('Multiple Roots', () => { } it('uses the same root in child components by default', () => { - expect.assertions(2) const pinia = createPinia() const useStore = defineMyStore() @@ -37,10 +35,12 @@ describe('Multiple Roots', () => { }, { global: { plugins: [pinia] } } ) + + const store = useStore() + expect(store.n).toBe(1) }) it('can use a new pinia root for all child components', async () => { - expect.assertions(2) const pinia = createPinia() const useStore = defineMyStore() @@ -64,35 +64,8 @@ describe('Multiple Roots', () => { }, { global: { plugins: [pinia] } } ) - }) - - it('state is shared between child components', async () => { - expect.assertions(3) - const pinia = createPinia() - const useStore = defineMyStore() - const ChildComponent = defineComponent({ - template: 'no', - props: { counter: { type: Number, required: true } }, - setup(props: { counter: number }) { - const store = useStore() - expect(store.n).toBe(props.counter) - store.n++ - }, - }) - mount( - { - template: - '', - components: { ChildComponent }, - setup() { - const store = useStore() - expect(store.n).toBe(0) - store.n++ - providePinia(createPinia()) - }, - }, - { global: { plugins: [pinia] } } - ) + const store = useStore() + expect(store.n).toBe(0) }) }) From f8fd0c847cb15fba60eb4ebc892d2ffef122e9ed Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 31 Mar 2022 10:55:30 +0200 Subject: [PATCH 3/3] test: add failing tests --- .../pinia/__tests__/multipleRoots.spec.ts | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/packages/pinia/__tests__/multipleRoots.spec.ts b/packages/pinia/__tests__/multipleRoots.spec.ts index bfd318301f..d0cc5702a0 100644 --- a/packages/pinia/__tests__/multipleRoots.spec.ts +++ b/packages/pinia/__tests__/multipleRoots.spec.ts @@ -11,24 +11,27 @@ describe('Multiple Roots', () => { }) } - it('uses the same root in child components by default', () => { + it('provides a pinia to children components', async () => { const pinia = createPinia() - const useStore = defineMyStore() + const useA = defineMyStore() + let nestedA!: ReturnType const ChildComponent = defineComponent({ template: 'no', setup() { - const store = useStore() - expect(store.n).toBe(1) + // should use the provided pinia by the parent + const store = useA() + nestedA = store + expect(store.n).toBe(0) }, }) - mount( { template: '', components: { ChildComponent }, setup() { - const store = useStore() + providePinia(createPinia()) + const store = useA() expect(store.n).toBe(0) store.n++ }, @@ -36,19 +39,28 @@ describe('Multiple Roots', () => { { global: { plugins: [pinia] } } ) - const store = useStore() + const store = useA() + // should be the parent one + expect(store).not.toBe(nestedA) expect(store.n).toBe(1) }) - it('can use a new pinia root for all child components', async () => { + it('should be able to use plugins', async () => { const pinia = createPinia() - const useStore = defineMyStore() + const useA = defineMyStore() + + // @ts-expect-error: type not defined + pinia.use(() => ({ parent: true })) const ChildComponent = defineComponent({ template: 'no', setup() { - const store = useStore() - expect(store.n).toBe(0) + // should use the provided pinia by the parent + const store = useA() + // @ts-expect-error: not defined + expect(store.parent).toBeUndefined() + // @ts-expect-error: not defined + expect(store.child).toBe(true) }, }) mount( @@ -56,16 +68,18 @@ describe('Multiple Roots', () => { template: '', components: { ChildComponent }, setup() { - providePinia(createPinia()) - const store = useStore() - expect(store.n).toBe(0) - store.n++ + const pinia = createPinia() + // @ts-expect-error: type not defined + pinia.use(() => ({ child: true })) + providePinia(pinia) + const store = useA() + // @ts-expect-error: not defined + expect(store.child).toBeUndefined() + // @ts-expect-error: not defined + expect(store.parent).toBe(true) }, }, { global: { plugins: [pinia] } } ) - - const store = useStore() - expect(store.n).toBe(0) }) })