Skip to content
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

feat: create useState composable #1402

Merged
merged 8 commits into from
Feb 13, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { defineComponent } from 'vue';
import Vuex, { Store } from 'vuex';
import { createLocalVue, mount, Wrapper } from '@vue/test-utils';
import { installNewXPlugin } from '../../__tests__/utils';
import { useState } from '../use-state';
import { searchBoxXStoreModule } from '../../x-modules/search-box/index';

const TestComponent = defineComponent({
setup() {
const searchBoxState = useState('searchBox', ['query', 'inputStatus']);
return {
searchBoxState
};
}
});

describe('testing useState composable', () => {
let component: Wrapper<any>;

beforeEach(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
component?.vm.$destroy();
jest.clearAllMocks();
const localVue = createLocalVue();
localVue.use(Vuex);

const store = new Store({
modules: {
x: {
namespaced: true,
modules: {
searchBox: { namespaced: true, ...searchBoxXStoreModule } as any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can type this part as AnyXStoreModule

Suggested change
searchBox: { namespaced: true, ...searchBoxXStoreModule } as any
searchBox: { namespaced: true, ...searchBoxXStoreModule } as AnyXStoreModule

}
}
}
});
installNewXPlugin({ store }, localVue);

component = mount(TestComponent, {
localVue,
store
});
});

it('maps store state', () => {
expect(component.vm.searchBoxState.query.value).toEqual('');
expect(component.vm.searchBoxState.inputStatus.value).toEqual('initial');

// eslint-disable-next-line @typescript-eslint/no-unsafe-call
component.vm.$store.commit('x/searchBox/setQuery', 'pork shoulder ');
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
component.vm.$store.commit('x/searchBox/setInputStatus', 'filled');

expect(component.vm.searchBoxState.query.value).toEqual('pork shoulder ');
expect(component.vm.searchBoxState.inputStatus.value).toEqual('filled');
});
});
1 change: 1 addition & 0 deletions packages/x-components/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './use-$x';
export * from './use-register-x-module';
export * from './use-on-display';
export * from './use-store';
export * from './use-state';
25 changes: 25 additions & 0 deletions packages/x-components/src/composables/use-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { computed, ComputedRef } from 'vue';
import { Dictionary } from '@empathyco/x-utils';
import { ExtractState, XModuleName } from '../x-modules/x-modules.types';
import { useStore } from './use-store';

/**
* Function which returns the selected state as a dictionary of paths.
*
* @param module - The {@link XModuleName} of the getter.
* @param paths - List of state paths.
* @returns The state properties of the module.
*
* @public
*/
export function useState<Module extends XModuleName, Paths extends keyof ExtractState<Module>>(
module: Module,
paths: Paths[]
): Dictionary<ComputedRef> {
const store = useStore();

return paths.reduce<Dictionary<ComputedRef>>((state, path) => {
state[path as string] = computed(() => store.state.x[module][path]);
return state;
}, {});
}
Loading