diff --git a/packages/pinia/__tests__/multipleRoots.spec.ts b/packages/pinia/__tests__/multipleRoots.spec.ts new file mode 100644 index 0000000000..d0cc5702a0 --- /dev/null +++ b/packages/pinia/__tests__/multipleRoots.spec.ts @@ -0,0 +1,85 @@ +import { createPinia, defineStore, providePinia } from '../src' +import { mount } from '@vue/test-utils' +import { defineComponent } from 'vue' + +describe('Multiple Roots', () => { + function defineMyStore() { + return defineStore('main', { + state: () => ({ + n: 0, + }), + }) + } + + it('provides a pinia to children components', async () => { + const pinia = createPinia() + const useA = defineMyStore() + let nestedA!: ReturnType + + const ChildComponent = defineComponent({ + template: 'no', + setup() { + // should use the provided pinia by the parent + const store = useA() + nestedA = store + expect(store.n).toBe(0) + }, + }) + mount( + { + template: '', + components: { ChildComponent }, + setup() { + providePinia(createPinia()) + const store = useA() + expect(store.n).toBe(0) + store.n++ + }, + }, + { global: { plugins: [pinia] } } + ) + + const store = useA() + // should be the parent one + expect(store).not.toBe(nestedA) + expect(store.n).toBe(1) + }) + + it('should be able to use plugins', async () => { + const pinia = createPinia() + const useA = defineMyStore() + + // @ts-expect-error: type not defined + pinia.use(() => ({ parent: true })) + + const ChildComponent = defineComponent({ + template: 'no', + setup() { + // 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( + { + template: '', + components: { ChildComponent }, + setup() { + 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] } } + ) + }) +}) 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. */