From: Eduardo San Martin Morote Date: Tue, 6 Apr 2021 17:52:56 +0000 (+0200) Subject: test: mapStores X-Git-Tag: v2.0.0-alpha.11~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=687d70513553d4db983e50ebf05bffbaabc0b22f;p=thirdparty%2Fvuejs%2Fpinia.git test: mapStores --- diff --git a/__tests__/mapHelpers.spec.ts b/__tests__/mapHelpers.spec.ts new file mode 100644 index 00000000..0b9ac834 --- /dev/null +++ b/__tests__/mapHelpers.spec.ts @@ -0,0 +1,113 @@ +import { createPinia, defineStore, mapStores, PiniaPlugin } from '../src' +import { createLocalVue, mount } from '@vue/test-utils' +import VueCompositionAPI, { + nextTick, + defineComponent, +} from '@vue/composition-api' + +describe('Map Helpers', () => { + const useCartStore = defineStore({ id: 'cart' }) + const useStore = defineStore({ + id: 'main', + state: () => ({ + a: true, + n: 0, + nested: { + foo: 'foo', + a: { b: 'string' }, + }, + }), + getters: { + double() { + return this.n * 2 + }, + notA() { + return !this.a + }, + }, + actions: { + doubleCount() { + this.n = this.n * 2 + }, + }, + }) + + const localVue = createLocalVue() + localVue.use(VueCompositionAPI) + localVue.use(PiniaPlugin) + + describe('mapStores', () => { + it('mapStores computes only once when mapping one store', async () => { + const pinia = createPinia() + const fromStore = jest.fn(function () { + // @ts-ignore + return this.mainStore + }) + const Component = defineComponent({ + template: `

{{ fromStore.n }}

`, + computed: { + ...mapStores(useStore), + fromStore, + }, + }) + + const wrapper = mount(Component, { localVue, pinia }) + // const store = useStore() + // const other = useCartStore() + expect(wrapper.vm.mainStore).toBeDefined() + expect(wrapper.text()).toBe('0') + await nextTick() + expect(fromStore).toHaveBeenCalledTimes(1) + + await wrapper.trigger('click') + expect(wrapper.text()).toBe('1') + expect(fromStore).toHaveBeenCalledTimes(1) + await wrapper.trigger('click') + expect(wrapper.text()).toBe('2') + expect(fromStore).toHaveBeenCalledTimes(1) + }) + + it('mapStores computes only once when mapping multiple stores', async () => { + const pinia = createPinia() + const fromStore = jest.fn(function () { + // @ts-ignore + return this.mainStore + }) + const Component = defineComponent({ + template: `

{{ mainStore.n }} {{ fromStore.n }} {{ cartStore.$id }}

`, + computed: { + ...mapStores(useStore, useCartStore), + fromStore, + }, + }) + + const wrapper = mount(Component, { localVue, pinia }) + expect(wrapper.text()).toBe('0 0 cart') + await nextTick() + // NOTE: it seems to be the same as the number of stores, probably because + // we use Vue.set + expect(fromStore).toHaveBeenCalledTimes(2) + + await wrapper.trigger('click') + expect(wrapper.text()).toBe('1 1 cart') + expect(fromStore).toHaveBeenCalledTimes(2) + await wrapper.trigger('click') + expect(wrapper.text()).toBe('2 2 cart') + expect(fromStore).toHaveBeenCalledTimes(2) + }) + }) + + // mapStores(useStore).main().$patch({ n: 20 }) + + const wrapper = mount(Component, { localVue, pinia }) + expect(wrapper.vm.main).toBeDefined() + const store = useStore() + expect(wrapper.text()).toBe('0 0') + expect(fromStore).toHaveBeenCalledTimes(1) + + store.n++ + await nextTick() + expect(wrapper.text()).toBe('1 1') + expect(fromStore).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/mapHelpers.ts b/src/mapHelpers.ts index 6eff181b..cdca90ea 100644 --- a/src/mapHelpers.ts +++ b/src/mapHelpers.ts @@ -7,7 +7,7 @@ type StoreObject = S extends StoreDefinition< infer Actions > ? { - [Id in Ids]: () => Store + [Id in `${Ids}Store`]: () => Store } : {} @@ -15,12 +15,32 @@ type Spread = A extends [infer L, ...infer R] ? StoreObject & Spread : unknown +/** + * Allows using stores without the composition API (`setup()`) by generating an object to be spread in the `computed` field of a component. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ export function mapStores( ...stores: [...Stores] ): Spread { return stores.reduce((reduced, useStore) => { - // @ts-ignore - reduced[useStore.$id] = function () { + // @ts-ignore: $id is added by defineStore + reduced[useStore.$id + 'Store'] = function () { return (useStore as GenericStoreDefinition)((this as any).$pinia) } return reduced