From bfc9ec80d771ea11f4bd8bbfeadd97627e4b9447 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:19:26 +0200 Subject: [PATCH 01/15] feat: migrate components to use composition API --- .../components/filters/renderless-filter.vue | 131 +++++++++--------- .../components/filters/simple-filter.vue | 88 ++++++------ 2 files changed, 111 insertions(+), 108 deletions(-) diff --git a/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue index f3096c30d0..bcdc45b5f9 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue @@ -1,11 +1,9 @@ diff --git a/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue index 83646d0b6c..6ef57fa5e9 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue @@ -2,7 +2,7 @@ @@ -43,61 +43,63 @@ From c22bd1bd2423d9dca1912f2f2910a0593bcf7c62 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:21:01 +0200 Subject: [PATCH 02/15] feat: add to playground --- packages/_vue3-migration-test/src/router.ts | 6 ++++++ .../src/x-modules/facets/components/index.ts | 1 + .../facets/components/test-filters.vue | 21 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue diff --git a/packages/_vue3-migration-test/src/router.ts b/packages/_vue3-migration-test/src/router.ts index ce5c957d29..754920da15 100644 --- a/packages/_vue3-migration-test/src/router.ts +++ b/packages/_vue3-migration-test/src/router.ts @@ -10,6 +10,7 @@ import { TestCrossFade, TestElementsList, TestFacets, + TestFilters, TestFade, TestScroll, TestSortDropdown, @@ -100,6 +101,11 @@ const routes = [ name: 'Facets', component: TestFacets }, + { + path: '/filters', + name: 'Filters', + component: TestFilters + }, { path: '/scroll', name: 'Scroll', diff --git a/packages/_vue3-migration-test/src/x-modules/facets/components/index.ts b/packages/_vue3-migration-test/src/x-modules/facets/components/index.ts index 82e5a09c6f..f996c15827 100644 --- a/packages/_vue3-migration-test/src/x-modules/facets/components/index.ts +++ b/packages/_vue3-migration-test/src/x-modules/facets/components/index.ts @@ -1 +1,2 @@ export { default as TestFacets } from './test-facets.vue'; +export { default as TestFilters } from './test-filters.vue'; diff --git a/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue b/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue new file mode 100644 index 0000000000..7bf05f3e52 --- /dev/null +++ b/packages/_vue3-migration-test/src/x-modules/facets/components/test-filters.vue @@ -0,0 +1,21 @@ + + + From c9df8e257aef64d989e5e6c2333216c53586d4ed Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:25:15 +0200 Subject: [PATCH 03/15] fix: unit test --- .../__tests__/renderless-filter.spec.ts | 65 +++++-------------- .../filters/__tests__/simple-filter.spec.ts | 6 +- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts index 8689b6316d..082282d26b 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts @@ -1,18 +1,17 @@ -import { BooleanFilter } from '@empathyco/x-types'; -import { mount, Wrapper } from '@vue/test-utils'; -import Vue from 'vue'; +import { mount } from '@vue/test-utils'; +import { nextTick, reactive } from 'vue'; import { getXComponentXModuleName, isXComponent } from '../../../../../components'; -import { XEventsTypes } from '../../../../../wiring/events.types'; import { createSimpleFilter, getSimpleFilterStub } from '../../../../../__stubs__/filters-stubs.factory'; -import { getDataTestSelector } from '../../../../../__tests__/utils'; +import { getDataTestSelector, installNewXPlugin } from '../../../../../__tests__/utils'; import RenderlessFilter from '../renderless-filter.vue'; +import { XPlugin } from '../../../../../plugins/x-plugin'; function renderComponent({ - filter = createSimpleFilter('category', 'food'), - clickEvents, + filter = reactive(createSimpleFilter('category', 'food')), + clickEvents = {}, template = ` ` -}: RenderOptions = {}): RenderAPI { - Vue.observable(filter); - const emit = jest.fn(); +} = {}) { + installNewXPlugin(); + + //Vue.observable(filter); + const wrapper = mount( { components: { RenderlessFilter }, @@ -41,11 +42,6 @@ function renderComponent({ propsData: { filter, clickEvents - }, - mocks: { - $x: { - emit - } } } ); @@ -54,14 +50,14 @@ function renderComponent({ return { wrapper: renderlessFilterWrapper, - emit, + emit: jest.spyOn(XPlugin.bus, 'emit'), filter, - clickFilter() { + clickFilter: () => { renderlessFilterWrapper.trigger('click'); }, - async selectFilter() { + selectFilter: async () => { filter.selected = true; - await Vue.nextTick(); + await nextTick(); } }; } @@ -80,7 +76,7 @@ describe('testing Renderless Filter component', () => { }); it('emits UserClickedAFilter and other custom events when clicked', () => { - const filter = getSimpleFilterStub(); + const filter = reactive(getSimpleFilterStub()); const { wrapper, clickFilter, emit } = renderComponent({ filter, clickEvents: { @@ -117,39 +113,14 @@ describe('testing Renderless Filter component', () => { }); it('disables the filter when it has no results', async () => { - const filter = createSimpleFilter('category', 'men', false); + const filter = reactive(createSimpleFilter('category', 'men', false)); const { wrapper } = renderComponent({ filter }); expect(wrapper.attributes('disabled')).toBeUndefined(); filter.totalResults = 0; - await wrapper.vm.$nextTick(); + await nextTick(); expect(wrapper.attributes('disabled')).toBe('disabled'); }); }); - -interface RenderOptions { - /** The template containing the {@link RenderlessFilter} component to render. */ - template?: string; - /** The filter data. Passed as prop to the {@link RenderlessFilter} component. */ - filter?: BooleanFilter; - /** - * Additional events to emit when the filter is clicked. - * Passed as prop to the {@link RenderlessFilter} component. - */ - clickEvents?: Partial; -} - -interface RenderAPI { - /** Wrapper of the {@link RenderlessFilter} component. */ - wrapper: Wrapper; - /** Mock of the {@link XBus.emit} function. */ - emit: jest.Mock; - /** The rendered filter data. */ - filter: BooleanFilter; - /** Fakes a click on the filter component. */ - clickFilter: () => void; - /** Sets the {@link RenderAPI.filter} `selected` property to `true`. */ - selectFilter: () => Promise; -} diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts index 8c1ff466d2..ee536e26f2 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts @@ -1,6 +1,6 @@ import { SimpleFilter as SimpleFilterModel } from '@empathyco/x-types'; import { mount, Wrapper } from '@vue/test-utils'; -import Vue from 'vue'; +import Vue, { nextTick } from 'vue'; import { createSimpleFilter } from '../../../../../__stubs__/filters-stubs.factory'; import { getDataTestSelector } from '../../../../../__tests__/utils'; import { getXComponentXModuleName, isXComponent } from '../../../../../components'; @@ -44,11 +44,11 @@ function renderSimpleFilter({ }, selectFilter() { filter.selected = true; - return Vue.nextTick(); + return nextTick(); }, updateFilter(newFields) { Object.assign(filter, newFields); - return Vue.nextTick(); + return nextTick(); } }; } From 8efce97e1edb415db7162832d5a7f9a462df4775 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:54:23 +0200 Subject: [PATCH 04/15] fix: playground error on console --- .../src/x-modules/facets/components/filters/simple-filter.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue index 6ef57fa5e9..fdf5cfa103 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue @@ -46,6 +46,7 @@ import { computed, defineComponent, PropType } from 'vue'; import { XEventsTypes } from '../../../../wiring/events.types'; import { facetsXModule } from '../../x-module'; + import RenderlessFilter from './renderless-filter.vue'; /** * Renders a simple filter, emitting the needed events when clicked. @@ -55,6 +56,7 @@ export default defineComponent({ name: 'SimpleFilter', xModule: facetsXModule.name, + components: { RenderlessFilter }, props: { /** The filter data to render. */ filter: { From c5d06297a840d230e4eb24c63ff7807689473aa5 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:31:40 +0200 Subject: [PATCH 05/15] fix: filter on playground --- .../x-modules/facets/components/filters/renderless-filter.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue index bcdc45b5f9..9464398e91 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue @@ -82,7 +82,7 @@ clickFilter: emitEvents, cssClasses: cssClasses.value, isDisabled: isDisabled.value - })?.[0] ?? h() + }) ?? h() ); }; } From d651cb22bd62bea199b4434b538830a5dd6b23f3 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:57:17 +0200 Subject: [PATCH 06/15] fix: fix filter on test --- .../__tests__/renderless-filter.spec.ts | 20 ++--- .../filters/__tests__/simple-filter.spec.ts | 81 +++++-------------- 2 files changed, 32 insertions(+), 69 deletions(-) diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts index 082282d26b..ef376d1148 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import { nextTick, reactive } from 'vue'; +import { nextTick, ref } from 'vue'; import { getXComponentXModuleName, isXComponent } from '../../../../../components'; import { createSimpleFilter, @@ -10,7 +10,7 @@ import RenderlessFilter from '../renderless-filter.vue'; import { XPlugin } from '../../../../../plugins/x-plugin'; function renderComponent({ - filter = reactive(createSimpleFilter('category', 'food')), + filter = ref(createSimpleFilter('category', 'food')), clickEvents = {}, template = ` { - filter.selected = true; + filter.value.selected = true; await nextTick(); } }; @@ -76,21 +76,21 @@ describe('testing Renderless Filter component', () => { }); it('emits UserClickedAFilter and other custom events when clicked', () => { - const filter = reactive(getSimpleFilterStub()); + const filter = ref(getSimpleFilterStub()); const { wrapper, clickFilter, emit } = renderComponent({ filter, clickEvents: { - UserClickedASimpleFilter: filter + UserClickedASimpleFilter: filter.value } }); clickFilter(); expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenCalledWith('UserClickedAFilter', filter, { + expect(emit).toHaveBeenCalledWith('UserClickedAFilter', filter.value, { target: wrapper.element }); - expect(emit).toHaveBeenCalledWith('UserClickedASimpleFilter', filter, { + expect(emit).toHaveBeenCalledWith('UserClickedASimpleFilter', filter.value, { target: wrapper.element }); }); @@ -99,7 +99,7 @@ describe('testing Renderless Filter component', () => { const { wrapper, filter } = renderComponent(); const customLabel = wrapper.find(getDataTestSelector('custom-label')); - expect(customLabel.text()).toEqual(filter.label); + expect(customLabel.text()).toEqual(filter.value.label); }); it('adds selected classes to the rendered element when the filter is selected', async () => { @@ -113,12 +113,12 @@ describe('testing Renderless Filter component', () => { }); it('disables the filter when it has no results', async () => { - const filter = reactive(createSimpleFilter('category', 'men', false)); + const filter = ref(createSimpleFilter('category', 'men', false)); const { wrapper } = renderComponent({ filter }); expect(wrapper.attributes('disabled')).toBeUndefined(); - filter.totalResults = 0; + filter.value.totalResults = 0; await nextTick(); expect(wrapper.attributes('disabled')).toBe('disabled'); diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts index ee536e26f2..0a79fc2e8f 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts @@ -1,19 +1,20 @@ -import { SimpleFilter as SimpleFilterModel } from '@empathyco/x-types'; -import { mount, Wrapper } from '@vue/test-utils'; -import Vue, { nextTick } from 'vue'; +import { mount } from '@vue/test-utils'; +import { nextTick, ref } from 'vue'; import { createSimpleFilter } from '../../../../../__stubs__/filters-stubs.factory'; -import { getDataTestSelector } from '../../../../../__tests__/utils'; +import { getDataTestSelector, installNewXPlugin } from '../../../../../__tests__/utils'; import { getXComponentXModuleName, isXComponent } from '../../../../../components'; -import { XEventsTypes } from '../../../../../wiring/events.types'; import SimpleFilter from '../simple-filter.vue'; +import { XPlugin } from '../../../../../plugins/index'; function renderSimpleFilter({ template = '', - filter = createSimpleFilter('category', 'women'), - clickEvents -}: RenderSimpleFilterOptions = {}): RenderSimpleFilterAPI { - Vue.observable(filter); - const emit = jest.fn(); + filter = ref(createSimpleFilter('category', 'women')), + clickEvents = {} +} = {}) { + //Vue.observable(filter); + + installNewXPlugin(); + const wrapper = mount( { components: { SimpleFilter }, @@ -24,11 +25,6 @@ function renderSimpleFilter({ propsData: { filter, clickEvents - }, - mocks: { - $x: { - emit - } } } ); @@ -37,16 +33,16 @@ function renderSimpleFilter({ return { wrapper: filterWrapper, - emit, + emit: jest.spyOn(XPlugin.bus, 'emit'), filter, - clickFilter() { + clickFilter: () => { wrapper.trigger('click'); }, - selectFilter() { - filter.selected = true; + selectFilter: () => { + filter.value.selected = true; return nextTick(); }, - updateFilter(newFields) { + updateFilter: (newFields: unknown) => { Object.assign(filter, newFields); return nextTick(); } @@ -69,7 +65,7 @@ describe('testing SimpleFilter component', () => { it('renders the provided filter by default', () => { const { wrapper, filter } = renderSimpleFilter(); - expect(wrapper.text()).toEqual(filter.label); + expect(wrapper.text()).toEqual(filter.value.label); }); it('emits `UserClickedAFilter` & `UserClickedASimpleFilter` events when clicked', () => { @@ -79,7 +75,7 @@ describe('testing SimpleFilter component', () => { expect(emit).toHaveBeenCalledTimes(2); ['UserClickedAFilter', 'UserClickedASimpleFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter, { target: wrapper.element }); + expect(emit).toHaveBeenCalledWith(event, filter.value, { target: wrapper.element }); }); }); @@ -92,7 +88,7 @@ describe('testing SimpleFilter component', () => { expect(emit).toHaveBeenCalledTimes(3); ['UserClickedAFilter', 'UserClickedASimpleFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter, { target: wrapper.element }); + expect(emit).toHaveBeenCalledWith(event, filter.value, { target: wrapper.element }); }); expect(emit).toHaveBeenNthCalledWith(3, 'UserAcceptedAQuery', 'potato', { target: wrapper.element @@ -111,7 +107,7 @@ describe('testing SimpleFilter component', () => { }); const customLabel = wrapper.find(getDataTestSelector('custom-label')); - expect(customLabel.text()).toEqual(filter.label); + expect(customLabel.text()).toEqual(filter.value.label); }); it('allows replacing the root element of the component', () => { @@ -131,12 +127,12 @@ describe('testing SimpleFilter component', () => { const labelWrapper = wrapper.get(getDataTestSelector('label')); const inputWrapper = wrapper.get(getDataTestSelector('input')); - expect(labelWrapper.text()).toBe(filter.label); + expect(labelWrapper.text()).toBe(filter.value.label); inputWrapper.trigger('change'); expect(emit).toHaveBeenCalledTimes(2); ['UserClickedAFilter', 'UserClickedASimpleFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter, { target: wrapper.element }); + expect(emit).toHaveBeenCalledWith(event, filter.value, { target: wrapper.element }); }); }); @@ -197,36 +193,3 @@ describe('testing SimpleFilter component', () => { expect(wrapper.classes()).toContain('x-simple-filter--is-selected'); }); }); - -interface RenderSimpleFilterOptions { - /** The events to emit when the filter is clicked. */ - clickEvents?: Partial; - /** The filter data to render. */ - filter?: SimpleFilterModel; - /** Template including the {@link SimpleFilter} to render. */ - template?: string; -} - -interface RenderSimpleFilterAPI { - /** Fakes a click in the {@link SimpleFilter} component. */ - clickFilter: () => void; - /** Mock for the {@link XBus.emit} function. */ - emit: jest.Mock; - /** The data rendered. */ - filter: SimpleFilterModel; - /** - * Selects the filter. - * - * @returns A promise that resolves after Vue updates the view. - */ - selectFilter: () => Promise; - /** - * Updates the rendered filter data. - * - * @param newFilter - The new fields to set to the rendered filter. - * @returns A promise that resolves after Vue updates the view. - */ - updateFilter: (newFilter: Partial) => Promise; - /** Test wrapper of the {@link SimpleFilter} component. */ - wrapper: Wrapper; -} From a91dd169f4999768ef08a2725a4f5c329c1afbff Mon Sep 17 00:00:00 2001 From: "Jose A. Cabaneros" Date: Fri, 21 Jun 2024 10:03:47 +0200 Subject: [PATCH 07/15] test(filters): fix unit tests --- .../__tests__/renderless-filter.spec.ts | 86 +++++++---------- .../filters/__tests__/simple-filter.spec.ts | 93 ++++++++----------- .../components/filters/renderless-filter.vue | 81 ++++++---------- .../components/filters/simple-filter.vue | 42 +++------ 4 files changed, 116 insertions(+), 186 deletions(-) diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts index ef376d1148..1827d83a42 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/renderless-filter.spec.ts @@ -9,29 +9,26 @@ import { getDataTestSelector, installNewXPlugin } from '../../../../../__tests__ import RenderlessFilter from '../renderless-filter.vue'; import { XPlugin } from '../../../../../plugins/x-plugin'; -function renderComponent({ +function render({ filter = ref(createSimpleFilter('category', 'food')), clickEvents = {}, template = ` - - - - ` + + + ` } = {}) { installNewXPlugin(); - //Vue.observable(filter); - const wrapper = mount( { components: { RenderlessFilter }, @@ -39,10 +36,7 @@ function renderComponent({ template }, { - propsData: { - filter, - clickEvents - } + propsData: { filter, clickEvents } } ); @@ -50,11 +44,9 @@ function renderComponent({ return { wrapper: renderlessFilterWrapper, - emit: jest.spyOn(XPlugin.bus, 'emit'), + emitSpy: jest.spyOn(XPlugin.bus, 'emit'), filter, - clickFilter: () => { - renderlessFilterWrapper.trigger('click'); - }, + clickFilter: () => renderlessFilterWrapper.trigger('click'), selectFilter: async () => { filter.value.selected = true; await nextTick(); @@ -63,47 +55,41 @@ function renderComponent({ } describe('testing Renderless Filter component', () => { - it('is an x-component', () => { - const { wrapper } = renderComponent(); - - expect(isXComponent(wrapper.vm)).toEqual(true); - }); - - it('belongs to the `facets` x-module', () => { - const { wrapper } = renderComponent(); + it('is an XComponent that belongs to the facets', () => { + const { wrapper } = render(); + expect(isXComponent(wrapper.vm)).toBeTruthy(); expect(getXComponentXModuleName(wrapper.vm)).toEqual('facets'); }); - it('emits UserClickedAFilter and other custom events when clicked', () => { + it('emits UserClickedAFilter and other custom events when clicked', async () => { const filter = ref(getSimpleFilterStub()); - const { wrapper, clickFilter, emit } = renderComponent({ + const { clickFilter, emitSpy } = render({ filter, - clickEvents: { - UserClickedASimpleFilter: filter.value - } + clickEvents: { UserClickedASimpleFilter: filter.value } }); + const metadata = { + moduleName: 'facets', + location: 'none', + replaceable: true + }; - clickFilter(); + await clickFilter(); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenCalledWith('UserClickedAFilter', filter.value, { - target: wrapper.element - }); - expect(emit).toHaveBeenCalledWith('UserClickedASimpleFilter', filter.value, { - target: wrapper.element - }); + expect(emitSpy).toHaveBeenCalledTimes(2); + expect(emitSpy).toHaveBeenCalledWith('UserClickedAFilter', filter.value, metadata); + expect(emitSpy).toHaveBeenCalledWith('UserClickedASimpleFilter', filter.value, metadata); }); it('allows customizing the rendered content with an slot', () => { - const { wrapper, filter } = renderComponent(); + const { wrapper, filter } = render(); const customLabel = wrapper.find(getDataTestSelector('custom-label')); expect(customLabel.text()).toEqual(filter.value.label); }); it('adds selected classes to the rendered element when the filter is selected', async () => { - const { wrapper, selectFilter } = renderComponent(); + const { wrapper, selectFilter } = render(); expect(wrapper.classes()).not.toContain('x-selected'); @@ -114,13 +100,13 @@ describe('testing Renderless Filter component', () => { it('disables the filter when it has no results', async () => { const filter = ref(createSimpleFilter('category', 'men', false)); - const { wrapper } = renderComponent({ filter }); + const { wrapper } = render({ filter }); expect(wrapper.attributes('disabled')).toBeUndefined(); filter.value.totalResults = 0; await nextTick(); - expect(wrapper.attributes('disabled')).toBe('disabled'); + expect(wrapper.attributes('disabled')).toEqual('disabled'); }); }); diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts index 0a79fc2e8f..c220c6b397 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/simple-filter.spec.ts @@ -6,13 +6,17 @@ import { getXComponentXModuleName, isXComponent } from '../../../../../component import SimpleFilter from '../simple-filter.vue'; import { XPlugin } from '../../../../../plugins/index'; -function renderSimpleFilter({ +const metadata = { + moduleName: 'facets', + location: 'none', + replaceable: true +}; + +function render({ template = '', filter = ref(createSimpleFilter('category', 'women')), clickEvents = {} } = {}) { - //Vue.observable(filter); - installNewXPlugin(); const wrapper = mount( @@ -22,10 +26,7 @@ function renderSimpleFilter({ template }, { - propsData: { - filter, - clickEvents - } + propsData: { filter, clickEvents } } ); @@ -33,77 +34,63 @@ function renderSimpleFilter({ return { wrapper: filterWrapper, - emit: jest.spyOn(XPlugin.bus, 'emit'), + emitSpy: jest.spyOn(XPlugin.bus, 'emit'), filter, - clickFilter: () => { - wrapper.trigger('click'); - }, + clickFilter: () => wrapper.trigger('click'), selectFilter: () => { filter.value.selected = true; return nextTick(); - }, - updateFilter: (newFields: unknown) => { - Object.assign(filter, newFields); - return nextTick(); } }; } describe('testing SimpleFilter component', () => { - it('is an x-component', () => { - const { wrapper } = renderSimpleFilter(); - - expect(isXComponent(wrapper.vm)).toEqual(true); - }); - - it('belongs to the `facets` x-module', () => { - const { wrapper } = renderSimpleFilter(); + it('is an XComponent that belongs to the facets', () => { + const { wrapper } = render(); + expect(isXComponent(wrapper.vm)).toBeTruthy(); expect(getXComponentXModuleName(wrapper.vm)).toEqual('facets'); }); it('renders the provided filter by default', () => { - const { wrapper, filter } = renderSimpleFilter(); + const { wrapper, filter } = render(); expect(wrapper.text()).toEqual(filter.value.label); }); - it('emits `UserClickedAFilter` & `UserClickedASimpleFilter` events when clicked', () => { - const { wrapper, clickFilter, emit, filter } = renderSimpleFilter(); + it('emits `UserClickedAFilter` & `UserClickedASimpleFilter` events when clicked', async () => { + const { clickFilter, emitSpy, filter } = render(); - clickFilter(); + await clickFilter(); - expect(emit).toHaveBeenCalledTimes(2); + expect(emitSpy).toHaveBeenCalledTimes(2); ['UserClickedAFilter', 'UserClickedASimpleFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter.value, { target: wrapper.element }); + expect(emitSpy).toHaveBeenCalledWith(event, filter.value, metadata); }); }); - it('emits configured events when clicked', () => { - const { wrapper, clickFilter, emit, filter } = renderSimpleFilter({ + it('emits configured events when clicked', async () => { + const { clickFilter, emitSpy, filter } = render({ clickEvents: { UserAcceptedAQuery: 'potato' } }); - clickFilter(); + await clickFilter(); - expect(emit).toHaveBeenCalledTimes(3); + expect(emitSpy).toHaveBeenCalledTimes(3); ['UserClickedAFilter', 'UserClickedASimpleFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter.value, { target: wrapper.element }); - }); - expect(emit).toHaveBeenNthCalledWith(3, 'UserAcceptedAQuery', 'potato', { - target: wrapper.element + expect(emitSpy).toHaveBeenCalledWith(event, filter.value, metadata); }); + expect(emitSpy).toHaveBeenNthCalledWith(3, 'UserAcceptedAQuery', 'potato', metadata); }); it('allows customizing the default button content', () => { - const { wrapper, filter } = renderSimpleFilter({ + const { wrapper, filter } = render({ template: ` - - ` + ` }); const customLabel = wrapper.find(getDataTestSelector('custom-label')); @@ -111,7 +98,7 @@ describe('testing SimpleFilter component', () => { }); it('allows replacing the root element of the component', () => { - const { wrapper, emit, filter } = renderSimpleFilter({ + const { wrapper, emitSpy, filter } = render({ template: ` - - ` + ` }); const labelWrapper = wrapper.get(getDataTestSelector('label')); const inputWrapper = wrapper.get(getDataTestSelector('input')); - expect(labelWrapper.text()).toBe(filter.value.label); + expect(labelWrapper.text()).toEqual(filter.value.label); inputWrapper.trigger('change'); - expect(emit).toHaveBeenCalledTimes(2); + expect(emitSpy).toHaveBeenCalledTimes(2); ['UserClickedAFilter', 'UserClickedASimpleFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter.value, { target: wrapper.element }); + expect(emitSpy).toHaveBeenCalledWith(event, filter.value, metadata); }); }); it('exposes proper css classes and attributes in the default slot', async () => { - const { wrapper, selectFilter, updateFilter } = renderSimpleFilter({ + const { wrapper, selectFilter, filter } = render({ template: ` { :aria-checked="filter.selected.toString()"> {{ filter.label }} - - ` + ` }); const buttonWrapper = wrapper.get(getDataTestSelector('button')); @@ -162,7 +147,7 @@ describe('testing SimpleFilter component', () => { expect(buttonWrapper.attributes()).toHaveProperty('aria-checked', 'false'); expect(buttonWrapper.element).toHaveProperty('disabled', false); - await selectFilter(); // Faking filter selection because XBus is mocked. + await selectFilter(); expect(buttonWrapper.attributes('aria-checked')).toBe('true'); expect(buttonWrapper.classes()).toHaveLength(4); expect(buttonWrapper.classes()).toEqual( @@ -174,15 +159,17 @@ describe('testing SimpleFilter component', () => { ]) ); - await updateFilter({ totalResults: 0 }); + filter.value.totalResults = 0; + await nextTick(); expect(buttonWrapper.element).toHaveProperty('disabled', true); - await updateFilter({ totalResults: undefined }); + filter.value.totalResults = undefined; + await nextTick(); expect(buttonWrapper.element).toHaveProperty('disabled', false); }); it('adds selected classes to the rendered element when the filter is selected', async () => { - const { wrapper, selectFilter } = renderSimpleFilter(); + const { wrapper, selectFilter } = render(); expect(wrapper.classes()).not.toContain('x-selected'); expect(wrapper.classes()).not.toContain('x-simple-filter--is-selected'); diff --git a/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue index 9464398e91..4875addf41 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/renderless-filter.vue @@ -1,24 +1,24 @@ diff --git a/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue b/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue index fdf5cfa103..3bd52a4ef0 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue +++ b/packages/x-components/src/x-modules/facets/components/filters/simple-filter.vue @@ -63,38 +63,20 @@ type: Object as PropType, required: true }, - /** - * Additional events, with their payload, to emit when the filter is clicked. - * - * @public - */ + /** Additional events, with their payload, to emit when the filter is clicked. */ clickEvents: Object as PropType> }, - setup: function (props) { - /** - * The {@link XEventsTypes} to emit. - * - * @returns The events to emit when clicked. - * @internal - */ - const clickEventsEmit = computed(() => { - return { - UserClickedASimpleFilter: props.filter, - ...props.clickEvents - }; - }); - - /** - * Dynamic CSS classes to apply to the component. - * - * @returns The dynamic CSS classes to apply to the component. - * @internal - */ - const cssClasses = computed(() => { - return { - 'x-simple-filter--is-selected': props.filter.selected - }; - }); + setup(props) { + /** The {@link XEventsTypes} to emit. */ + const clickEventsEmit = computed(() => ({ + UserClickedASimpleFilter: props.filter, + ...props.clickEvents + })); + + /** Dynamic CSS classes to apply to the component. */ + const cssClasses = computed(() => ({ + 'x-simple-filter--is-selected': props.filter.selected + })); return { clickEventsEmit, From a282c367d2485809f27a249187f79b98c1cc7759 Mon Sep 17 00:00:00 2001 From: Andrea Delgado <114981520+andreadlgdo@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:00:16 +0200 Subject: [PATCH 08/15] fix: fix unit test --- .../__tests__/hierarchical-filter.spec.ts | 219 ++++-------------- .../__tests__/number-range-filter.spec.ts | 87 +++---- 2 files changed, 83 insertions(+), 223 deletions(-) diff --git a/packages/x-components/src/x-modules/facets/components/filters/__tests__/hierarchical-filter.spec.ts b/packages/x-components/src/x-modules/facets/components/filters/__tests__/hierarchical-filter.spec.ts index f1fb2c4d45..fed226ae45 100644 --- a/packages/x-components/src/x-modules/facets/components/filters/__tests__/hierarchical-filter.spec.ts +++ b/packages/x-components/src/x-modules/facets/components/filters/__tests__/hierarchical-filter.spec.ts @@ -1,20 +1,21 @@ -import { - HierarchicalFacet, - HierarchicalFilter as HierarchicalFilterModel -} from '@empathyco/x-types'; +import { HierarchicalFilter as HierarchicalFilterModel } from '@empathyco/x-types'; import { mount, Wrapper, WrapperArray } from '@vue/test-utils'; -import Vue from 'vue'; import { createHierarchicalFacetStub } from '../../../../../__stubs__/facets-stubs.factory'; import { getDataTestSelector, installNewXPlugin } from '../../../../../__tests__/utils'; import { getXComponentXModuleName, isXComponent } from '../../../../../components'; import { XPlugin } from '../../../../../plugins/x-plugin'; -import { XEventsTypes } from '../../../../../wiring/events.types'; import { flatHierarchicalFilters } from '../../../utils'; import { facetsXModule } from '../../../x-module'; import { resetXFacetsStateWith } from '../../__tests__/utils'; import HierarchicalFilter from '../hierarchical-filter.vue'; -function renderHierarchicalFilter({ +const metadata = { + moduleName: 'facets', + location: 'none', + replaceable: true +}; + +function render({ template = ` { it('is an x-component', () => { - const { hierarchicalFilterWrapper } = renderHierarchicalFilter(); + const { hierarchicalFilterWrapper } = render(); expect(isXComponent(hierarchicalFilterWrapper.vm)).toEqual(true); }); it('belongs to the `facets` x-module', () => { - const { hierarchicalFilterWrapper } = renderHierarchicalFilter(); + const { hierarchicalFilterWrapper } = render(); expect(getXComponentXModuleName(hierarchicalFilterWrapper.vm)).toEqual('facets'); }); it('renders the provided filter by default', () => { - const { getFilterWrapper, getRootFilter } = renderHierarchicalFilter(); + const { getFilterWrapper, getRootFilter } = render(); expect(getFilterWrapper().text()).toEqual(getRootFilter().label); }); it('emits `UserClickedAFilter` and `UserClickedAHierarchicalFilter` event when clicked', () => { - const { getFilterWrapper, clickFilter, emit, getRootFilter } = renderHierarchicalFilter(); + const { clickFilter, emitSpy, getRootFilter } = render(); const filter = getRootFilter(); clickFilter(); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenCalledWith('UserClickedAFilter', filter, { - target: getFilterWrapper().element, - moduleName: 'facets', - location: undefined, - replaceable: true - }); - expect(emit).toHaveBeenCalledWith('UserClickedAHierarchicalFilter', filter, { - target: getFilterWrapper().element, - moduleName: 'facets', - location: undefined, - replaceable: true - }); + expect(emitSpy).toHaveBeenCalledTimes(2); + expect(emitSpy).toHaveBeenCalledWith('UserClickedAFilter', filter, metadata); + expect(emitSpy).toHaveBeenCalledWith('UserClickedAHierarchicalFilter', filter, metadata); }); it('emits configured events when clicked', () => { - const { getFilterWrapper, clickFilter, emit, getRootFilter } = renderHierarchicalFilter({ + const { clickFilter, emitSpy, getRootFilter } = render({ clickEvents: { UserAcceptedAQuery: 'potato', UserBlurredSearchBox: undefined @@ -167,31 +157,16 @@ describe('testing `HierarchicalFilter` component', () => { const filter = getRootFilter(); clickFilter(); - expect(emit).toHaveBeenCalledTimes(4); + expect(emitSpy).toHaveBeenCalledTimes(4); ['UserClickedAFilter', 'UserClickedAHierarchicalFilter'].forEach(event => { - expect(emit).toHaveBeenCalledWith(event, filter, { - target: getFilterWrapper().element, - moduleName: 'facets', - location: undefined, - replaceable: true - }); - }); - expect(emit).toHaveBeenCalledWith('UserAcceptedAQuery', 'potato', { - target: getFilterWrapper().element, - moduleName: 'facets', - location: undefined, - replaceable: true - }); - expect(emit).toHaveBeenCalledWith('UserBlurredSearchBox', undefined, { - target: getFilterWrapper().element, - moduleName: 'facets', - location: undefined, - replaceable: true + expect(emitSpy).toHaveBeenCalledWith(event, filter, metadata); }); + expect(emitSpy).toHaveBeenCalledWith('UserAcceptedAQuery', 'potato', metadata); + expect(emitSpy).toHaveBeenCalledWith('UserBlurredSearchBox', undefined, metadata); }); it('allows replacing the root element of the component', () => { - const { hierarchicalFilterWrapper, getRootFilter, emit } = renderHierarchicalFilter({ + const { hierarchicalFilterWrapper, getRootFilter, emitSpy } = render({ template: ` { customInputWrapper.trigger('change'); - expect(emit).toHaveBeenCalledTimes(2); - const expectedMetadata = { - target: customLabelWrapper.element, - moduleName: 'facets', - location: undefined, - replaceable: true - }; - expect(emit).toHaveBeenCalledWith('UserClickedAFilter', filter, expectedMetadata); - expect(emit).toHaveBeenCalledWith('UserClickedAHierarchicalFilter', filter, expectedMetadata); + expect(emitSpy).toHaveBeenCalledTimes(2); + + expect(emitSpy).toHaveBeenCalledWith('UserClickedAFilter', filter, metadata); + expect(emitSpy).toHaveBeenCalledWith('UserClickedAHierarchicalFilter', filter, metadata); }); it('allows customizing the rendered label content with an slot', () => { - const { getFilterWrapper, getRootFilter } = renderHierarchicalFilter({ + const { getFilterWrapper, getRootFilter } = render({ template: `