From 96d0604f43033715f62e1bf1fa28051c79a76246 Mon Sep 17 00:00:00 2001 From: "Jose A. Cabaneros" Date: Fri, 5 Jul 2024 13:39:44 +0200 Subject: [PATCH 1/4] feat(display-emitter): support Vue3 to the component --- .../src/components/index.ts | 1 + .../src/components/test-display-emitter.vue | 43 +++++++ packages/_vue3-migration-test/src/main.ts | 3 +- packages/_vue3-migration-test/src/router.ts | 8 +- .../__tests__/display-emitter.spec.ts | 119 +++++++----------- .../src/components/display-emitter.vue | 71 ++++++----- 6 files changed, 135 insertions(+), 110 deletions(-) create mode 100644 packages/_vue3-migration-test/src/components/test-display-emitter.vue diff --git a/packages/_vue3-migration-test/src/components/index.ts b/packages/_vue3-migration-test/src/components/index.ts index c845db065a..89b6286ed2 100644 --- a/packages/_vue3-migration-test/src/components/index.ts +++ b/packages/_vue3-migration-test/src/components/index.ts @@ -17,3 +17,4 @@ export { default as TestBaseIdModal } from './modals/test-base-id-modal.vue'; export { default as TestExtraParams } from './extra-params/test-extra-params.vue'; export { default as TestSearch } from './test-search.vue'; export { default as TestTagging } from './tagging/test-tagging.vue'; +export { default as TestDisplayEmitter } from './test-display-emitter.vue'; diff --git a/packages/_vue3-migration-test/src/components/test-display-emitter.vue b/packages/_vue3-migration-test/src/components/test-display-emitter.vue new file mode 100644 index 0000000000..29b8fa6463 --- /dev/null +++ b/packages/_vue3-migration-test/src/components/test-display-emitter.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/packages/_vue3-migration-test/src/main.ts b/packages/_vue3-migration-test/src/main.ts index e23a9f174f..4e84127d08 100644 --- a/packages/_vue3-migration-test/src/main.ts +++ b/packages/_vue3-migration-test/src/main.ts @@ -73,7 +73,8 @@ const adapter = { identifierResults: () => new Promise(resolve => resolve({ results: ['123A', '123B', '123C', '123D'].map(id => createResultStub(id)) }) - ) + ), + tagging: () => new Promise(resolve => resolve()) } as unknown as XComponentsAdapter; const store = createStore({}); diff --git a/packages/_vue3-migration-test/src/router.ts b/packages/_vue3-migration-test/src/router.ts index ce24a8afac..d62ee3cbcd 100644 --- a/packages/_vue3-migration-test/src/router.ts +++ b/packages/_vue3-migration-test/src/router.ts @@ -45,7 +45,8 @@ import { TestRedirection, TestExtraParams, TestSearch, - TestTagging + TestTagging, + TestDisplayEmitter } from './'; const routes = [ @@ -278,6 +279,11 @@ const routes = [ path: '/tagging', name: 'Tagging', component: TestTagging + }, + { + path: '/display-emitter', + name: 'DisplayEmitter', + component: TestDisplayEmitter } ]; diff --git a/packages/x-components/src/components/__tests__/display-emitter.spec.ts b/packages/x-components/src/components/__tests__/display-emitter.spec.ts index 6f6285106a..25819f36d3 100644 --- a/packages/x-components/src/components/__tests__/display-emitter.spec.ts +++ b/packages/x-components/src/components/__tests__/display-emitter.spec.ts @@ -1,115 +1,86 @@ -import { mount, Wrapper } from '@vue/test-utils'; -import Vue, { ref, nextTick, Ref } from 'vue'; -import { TaggingRequest } from '@empathyco/x-types'; +import { mount } from '@vue/test-utils'; +import { nextTick } from 'vue'; import { useEmitDisplayEvent } from '../../composables/use-on-display'; import DisplayEmitter from '../display-emitter.vue'; import { getDataTestSelector } from '../../__tests__/utils'; +import { getXComponentXModuleName, isXComponent } from '../x-component.utils'; jest.mock('../../composables/use-on-display', () => ({ useEmitDisplayEvent: jest.fn() })); - -let emitDisplayEventElementSpy: Ref = ref(null); -let emitDisplayEventPayloadSpy: TaggingRequest = { url: '', params: {} }; const unwatchDisplaySpy = jest.fn(); -const refElementVisibility = ref(false); -(useEmitDisplayEvent as jest.Mock).mockImplementation(({ element, taggingRequest }) => { - // jest doesn't handle well evaluation of dynamic references with `toHaveBeenCalledWith` - // so we need a spy - emitDisplayEventElementSpy = element; - emitDisplayEventPayloadSpy = taggingRequest; - - return { - isElementVisible: refElementVisibility, - unwatchDisplay: unwatchDisplaySpy - }; -}); - -/** - * Renders the {@link DisplayEmitter} component, exposing a basic API for testing. - * - * @param options - The options to render the component with. - * - * @returns The API for testing the `DisplayEmitter` component. - */ -function renderDisplayEmitter( - { payload }: RenderDisplayEmitterOptions = { payload: { url: '', params: {} } } -): RenderDisplayEmitterAPI { - const wrapper = mount( - { - components: { - DisplayEmitter - }, - template: ` - -
- `, - props: ['payload'] - }, - { - propsData: { - payload - } - } - ); +(useEmitDisplayEvent as jest.Mock).mockReturnValue({ unwatchDisplay: unwatchDisplaySpy }); + +function render({ + payload = { url: 'tagging/url', params: { test: 'param' } }, + eventMetadata = { test: 'param' } +} = {}) { + const wrapper = mount({ + components: { DisplayEmitter }, + template: ` + +
+ `, + data: () => ({ payload, eventMetadata }) + }); return { - wrapper + wrapper: wrapper.findComponent(DisplayEmitter), + element: wrapper.find(getDataTestSelector('child')).element, + payload, + eventMetadata }; } describe('testing DisplayEmitter component', () => { beforeEach(() => { - refElementVisibility.value = false; + (useEmitDisplayEvent as jest.Mock).mockClear(); + unwatchDisplaySpy.mockClear(); + }); + + it('is an XComponent which has an XModule', () => { + const { wrapper } = render(); + + expect(isXComponent(wrapper.vm)).toBeTruthy(); + expect(getXComponentXModuleName(wrapper.vm)).toEqual('tagging'); }); it('renders everything passed to its default slot', () => { - const { wrapper } = renderDisplayEmitter(); + const { wrapper } = render(); - expect(wrapper.find(getDataTestSelector('child')).exists()).toBe(true); + expect(wrapper.find(getDataTestSelector('child')).exists()).toBeTruthy(); }); - it('uses `useEmitDisplayEvent` underneath', () => { - renderDisplayEmitter(); + it('executes `useEmitDisplayEvent` composable underneath', () => { + render(); expect(useEmitDisplayEvent).toHaveBeenCalled(); }); it('provides `useEmitDisplayEvent` with the element in the slot to watch', async () => { - renderDisplayEmitter(); + const { element } = render(); await nextTick(); - expect(emitDisplayEventElementSpy.value).not.toBe(null); - expect(emitDisplayEventElementSpy.value?.$el.getAttribute('data-test')).toBe('child'); + expect(useEmitDisplayEvent).toHaveBeenCalledWith(expect.objectContaining({ element })); }); - // eslint-disable-next-line max-len - it('provides `useEmitDisplayEvent` with the payload to emit with the display event', () => { - const payload = { url: 'test-url', params: { test: 'param' } }; - renderDisplayEmitter({ - payload - }); + it('provides `useEmitDisplayEvent` with the payload and metadata to emit with the display event', async () => { + const { payload, eventMetadata } = render(); - expect(useEmitDisplayEvent).toHaveBeenCalled(); - expect(emitDisplayEventPayloadSpy).toBe(payload); + await nextTick(); + + expect(useEmitDisplayEvent).toHaveBeenCalledWith( + expect.objectContaining({ taggingRequest: payload, eventMetadata }) + ); }); it('removes the watcher on unmount', async () => { - const { wrapper } = renderDisplayEmitter(); + const { wrapper } = render(); wrapper.destroy(); await nextTick(); + expect(unwatchDisplaySpy).toHaveBeenCalled(); }); }); - -interface RenderDisplayEmitterOptions { - /** The payload to provide. */ - payload?: TaggingRequest; -} - -interface RenderDisplayEmitterAPI { - /** The wrapper testing component instance. */ - wrapper: Wrapper; -} diff --git a/packages/x-components/src/components/display-emitter.vue b/packages/x-components/src/components/display-emitter.vue index bd5e18229e..fe4ec0bb68 100644 --- a/packages/x-components/src/components/display-emitter.vue +++ b/packages/x-components/src/components/display-emitter.vue @@ -1,55 +1,58 @@ - - From 66188b7715f2f161f59e0c4ea523ca6cc3c7fd0f Mon Sep 17 00:00:00 2001 From: "Jose A. Cabaneros" Date: Wed, 10 Jul 2024 16:27:58 +0200 Subject: [PATCH 2/4] fix(display-emitter): avoid register tagging x-module --- packages/x-components/src/components/display-emitter.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/x-components/src/components/display-emitter.vue b/packages/x-components/src/components/display-emitter.vue index fe4ec0bb68..3ece1ac6f6 100644 --- a/packages/x-components/src/components/display-emitter.vue +++ b/packages/x-components/src/components/display-emitter.vue @@ -11,12 +11,10 @@ import { TaggingRequest } from '@empathyco/x-types'; import { useEmitDisplayEvent } from '../composables/use-on-display'; import { WireMetadata } from '../wiring'; - import { taggingXModule } from '../x-modules/tagging/x-module'; /** A component that emits a display event when it first appears in the viewport. */ export default defineComponent({ name: 'DisplayEmitter', - xModule: taggingXModule.name, props: { /** The payload for the display event emit. */ payload: { From c8d268861696abaa3bbaef2e15c7337904ffac26 Mon Sep 17 00:00:00 2001 From: "Jose A. Cabaneros" Date: Wed, 10 Jul 2024 16:56:10 +0200 Subject: [PATCH 3/4] test(display-emitter): avoid register tagging x-module --- .../src/components/__tests__/display-emitter.spec.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/x-components/src/components/__tests__/display-emitter.spec.ts b/packages/x-components/src/components/__tests__/display-emitter.spec.ts index 25819f36d3..0a436d073d 100644 --- a/packages/x-components/src/components/__tests__/display-emitter.spec.ts +++ b/packages/x-components/src/components/__tests__/display-emitter.spec.ts @@ -3,7 +3,6 @@ import { nextTick } from 'vue'; import { useEmitDisplayEvent } from '../../composables/use-on-display'; import DisplayEmitter from '../display-emitter.vue'; import { getDataTestSelector } from '../../__tests__/utils'; -import { getXComponentXModuleName, isXComponent } from '../x-component.utils'; jest.mock('../../composables/use-on-display', () => ({ useEmitDisplayEvent: jest.fn() @@ -38,13 +37,6 @@ describe('testing DisplayEmitter component', () => { unwatchDisplaySpy.mockClear(); }); - it('is an XComponent which has an XModule', () => { - const { wrapper } = render(); - - expect(isXComponent(wrapper.vm)).toBeTruthy(); - expect(getXComponentXModuleName(wrapper.vm)).toEqual('tagging'); - }); - it('renders everything passed to its default slot', () => { const { wrapper } = render(); From d81e7e0ceba005ca8e47be40d677a6e24e278b32 Mon Sep 17 00:00:00 2001 From: "Jose A. Cabaneros" Date: Thu, 11 Jul 2024 11:14:45 +0200 Subject: [PATCH 4/4] fix(display-emitter): handle possible unwatchDisplay undefined --- packages/x-components/src/components/display-emitter.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-components/src/components/display-emitter.vue b/packages/x-components/src/components/display-emitter.vue index 3ece1ac6f6..ee55f2881c 100644 --- a/packages/x-components/src/components/display-emitter.vue +++ b/packages/x-components/src/components/display-emitter.vue @@ -27,7 +27,7 @@ } }, setup(props, { slots }) { - let unwatchDisplay: WatchStopHandle; + let unwatchDisplay: WatchStopHandle | undefined; onMounted(() => { const element = getCurrentInstance()?.proxy.$el as HTMLElement | undefined; @@ -41,7 +41,7 @@ }); onUnmounted(() => { - unwatchDisplay(); + unwatchDisplay?.(); }); /*