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: Migrate query suggestions module to composition api #1497

Merged
2 changes: 1 addition & 1 deletion packages/_vue3-migration-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@vueuse/core": "~10.7.1",
"vue": "^3.4.22",
"vue-router": "^4.3.0",
"vuex": "^4.1.0"
"vuex": "4.0.2"
Copy link
Member

@joseacabaneros joseacabaneros Jun 11, 2024

Choose a reason for hiding this comment

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

Reactivity of vuex getters is broken in 4.1.0 when registering store modules dynamically. vuejs/vuex#2217
vuejs/vuex#2197
It caused emitters didn't work when the trigger is a getter and not the state (request getter of QuerySuggestions x-module).
Downgraded to 4.0.2

},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
Expand Down
10 changes: 8 additions & 2 deletions packages/_vue3-migration-test/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { XComponentsAdapter } from '@empathyco/x-types';
import { QuerySuggestionsRequest, XComponentsAdapter } from '@empathyco/x-types';
import { Component, configureCompat, createApp } from 'vue';
import { createStore } from 'vuex';
import { xPlugin } from '../../x-components/src/plugins/x-plugin';
import { getQuerySuggestionsStub } from '../../x-components/src/__stubs__/query-suggestions-stubs.factory';
import App from './App.vue';
import router from './router';
import { facetsXModule, nextQueriesXModule, scrollXModule, searchXModule } from './';
Expand All @@ -26,7 +27,12 @@ if (VUE_COMPAT_MODE === 2) {
});
}

const adapter = {} as XComponentsAdapter;
const adapter = {
querySuggestions: (request: QuerySuggestionsRequest) =>
new Promise(resolve => {
resolve({ suggestions: getQuerySuggestionsStub(request.query, 5) });
})
} as XComponentsAdapter;

const store = createStore({});

Expand Down
8 changes: 7 additions & 1 deletion packages/_vue3-migration-test/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import {
TestBaseKeyboardNavigation,
TestPartialResultsList,
TestBaseEventsModal,
TestBaseIdModal
TestBaseIdModal,
TestQuerySuggestions
} from './';

const routes = [
Expand Down Expand Up @@ -194,6 +195,11 @@ const routes = [
path: '/test-base-id-modal',
name: 'TestBaseIdModal',
component: TestBaseIdModal
},
{
path: '/query-suggestions',
name: 'QuerySuggestions',
component: TestQuerySuggestions
}
];

Expand Down
4 changes: 4 additions & 0 deletions packages/_vue3-migration-test/src/x-modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ export * from './search';
export * from './search-box';
export { default as TestElementsList } from './test-elements-list.vue';
export * from './scroll';
<<<<<<< feat/EMP-4163-migrate-query-suggestions-module-to-composition-api
export * from './query-suggestions';
=======
export * from './history-queries';
>>>>>>> main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as TestQuerySuggestions } from './test-query-suggestions.vue';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<template>
<SearchInput />
<QuerySuggestions />
</template>

<script setup>
import SearchInput from '../../../../../x-components/src/x-modules/search-box/components/search-input.vue';
import QuerySuggestions from '../../../../../x-components/src/x-modules/query-suggestions/components/query-suggestions.vue';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components';
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('testing plugin alias', () => {
identifierResults: undefined,
nextQueries: undefined,
popularSearches: undefined,
querySuggestions: undefined,
querySuggestions: 'initial', // It is already registered by the `querySuggestionsXModule` import itself
recommendations: undefined,
relatedTags: undefined,
search: undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Suggestion } from '@empathyco/x-types';
import { DeepPartial } from '@empathyco/x-utils';
import { createLocalVue, mount, Wrapper } from '@vue/test-utils';
import { createLocalVue, mount } from '@vue/test-utils';
import Vuex, { Store } from 'vuex';
import { createQuerySuggestion } from '../../../../__stubs__/query-suggestions-stubs.factory';
import { getDataTestSelector, installNewXPlugin } from '../../../../__tests__/utils';
Expand All @@ -15,50 +14,49 @@ import { resetXQuerySuggestionsStateWith } from './utils';
function renderQuerySuggestion({
suggestion = createQuerySuggestion('baileys'),
query = '',
template = '<QuerySuggestion v-bind="$attrs"/>'
}: RenderQuerySuggestionOptions = {}): RenderQuerySuggestionApi {
template = '<QuerySuggestion :suggestion="suggestion"/>'
} = {}) {
const localVue = createLocalVue();
localVue.use(Vuex);
const store = new Store<DeepPartial<RootXStoreState>>({});

installNewXPlugin({ store, initialXModules: [querySuggestionsXModule] }, localVue);
resetXQuerySuggestionsStateWith(store, { query });

const wrapper = mount(
{
template,
inheritAttrs: false,
components: {
QuerySuggestion
}
components: { QuerySuggestion },
props: ['suggestion']
},
{
localVue,
propsData: { suggestion },
store
store,
propsData: { suggestion }
}
);

return {
wrapper: wrapper.findComponent(QuerySuggestion),
suggestion,
emitSpy: jest.spyOn(XPlugin.bus, 'emit'),
getMatchingPart() {
return wrapper.get(getDataTestSelector('matching-part'));
}
};
getMatchingPart: () => wrapper.get(getDataTestSelector('matching-part'))
} as const;
}

describe('testing query-suggestion component', () => {
it('is an XComponent that belongs to the query suggestions', () => {
const { wrapper } = renderQuerySuggestion();
expect(isXComponent(wrapper.vm)).toEqual(true);

expect(isXComponent(wrapper.vm)).toBeTruthy();
expect(getXComponentXModuleName(wrapper.vm)).toEqual('querySuggestions');
});

it('renders the suggestion received as prop', () => {
const { wrapper } = renderQuerySuggestion({
suggestion: createQuerySuggestion('milk')
});

expect(wrapper.text()).toEqual('milk');
});

Expand Down Expand Up @@ -97,33 +95,12 @@ describe('testing query-suggestion component', () => {
const { wrapper } = renderQuerySuggestion({
suggestion: createQuerySuggestion('baileys'),
template: `
<QuerySuggestion v-bind="$attrs" #default="{ suggestion }">
<QuerySuggestion :suggestion="suggestion" #default="{ suggestion }">
<span>🔍</span>
<span>{{ suggestion.query }}</span>
</QuerySuggestion>
`
</QuerySuggestion>`
});

expect(wrapper.text()).toEqual('🔍 baileys');
});
});

interface RenderQuerySuggestionOptions {
/** The suggestion data to render. */
suggestion?: Suggestion;
/** The query that the suggestions belong to. */
query?: string;
/** The template to render. */
template?: string;
}

interface RenderQuerySuggestionApi {
/** Testing wrapper of the {@link QuerySuggestion} component. */
wrapper: Wrapper<Vue>;
/** Retrieves the wrapper that matches the query in the {@link QuerySuggestion} component. */
getMatchingPart: () => Wrapper<Vue>;
/** The {@link XBus.emit} spy. */
emitSpy: jest.SpyInstance;
/** Rendered {@link Suggestion} model data. */
suggestion: Suggestion;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Suggestion } from '@empathyco/x-types';
import { DeepPartial } from '@empathyco/x-utils';
import { createLocalVue, mount, Wrapper, WrapperArray } from '@vue/test-utils';
import { createLocalVue, mount } from '@vue/test-utils';
import Vuex, { Store } from 'vuex';
import { createQuerySuggestion } from '../../../../__stubs__/query-suggestions-stubs.factory';
import { getDataTestSelector, installNewXPlugin } from '../../../../__tests__/utils';
Expand All @@ -16,54 +15,48 @@ function renderQuerySuggestions({
createQuerySuggestion('milk chocolate'),
createQuerySuggestion('chocolate milk')
],
maxItemsToRender,
maxItemsToRender = 5,
template = '<QuerySuggestions v-bind="$attrs" />'
}: RenderQuerySuggestionsOptions = {}): RenderQuerySuggestionsApi {
} = {}) {
const localVue = createLocalVue();
localVue.use(Vuex);
const store = new Store<DeepPartial<RootXStoreState>>({});

installNewXPlugin({ store, initialXModules: [querySuggestionsXModule] }, localVue);
resetXQuerySuggestionsStateWith(store, { suggestions });

const wrapper = mount(
{
template,
inheritAttrs: false,
components: {
QuerySuggestions
}
components: { QuerySuggestions }
},
{
localVue,
store,
propsData: {
maxItemsToRender
}
propsData: { maxItemsToRender }
}
);

return {
wrapper: wrapper.findComponent(QuerySuggestions),
suggestions,
async setMaxItemsToRender(max) {
return await wrapper.setProps({ maxItemsToRender: max });
},
getSuggestionItemWrappers() {
return wrapper.findAll(getDataTestSelector('suggestion-item'));
}
getSuggestionItemWrappers: () => wrapper.findAll(getDataTestSelector('suggestion-item'))
};
}

describe('testing Query Suggestions component', () => {
it('is an XComponent that belongs to the query suggestions module', () => {
const { wrapper } = renderQuerySuggestions();
expect(isXComponent(wrapper.vm)).toEqual(true);

expect(isXComponent(wrapper.vm)).toBeTruthy();
expect(getXComponentXModuleName(wrapper.vm)).toEqual('querySuggestions');
});

it('does not render anything when suggestions are empty', () => {
const { wrapper } = renderQuerySuggestions({ suggestions: [] });
expect(wrapper.html()).toBe('');

expect(wrapper.html()).toEqual('');
});

it('renders the state list of suggestions', () => {
Expand All @@ -87,8 +80,7 @@ describe('testing Query Suggestions component', () => {
<span>🔍</span>
<span>{{ suggestion.query }}</span>
</button>
</QuerySuggestions>
`
</QuerySuggestions>`
});

const suggestionItemWrappers = getSuggestionItemWrappers();
Expand All @@ -108,8 +100,7 @@ describe('testing Query Suggestions component', () => {
<QuerySuggestions #suggestion-content="{ suggestion }">
<span>🔍</span>
<span>{{ suggestion.query }}</span>
</QuerySuggestions>
`
</QuerySuggestions>`
});

const suggestionItemWrappers = getSuggestionItemWrappers();
Expand All @@ -120,9 +111,8 @@ describe('testing Query Suggestions component', () => {
});
});

// eslint-disable-next-line max-len
it('renders at most the number of QuerySuggestion defined by `maxItemsToRender` prop', async () => {
const { getSuggestionItemWrappers, setMaxItemsToRender, suggestions } = renderQuerySuggestions({
const { wrapper, getSuggestionItemWrappers, suggestions } = renderQuerySuggestions({
suggestions: [
createQuerySuggestion('shirt'),
createQuerySuggestion('jeans'),
Expand All @@ -131,33 +121,13 @@ describe('testing Query Suggestions component', () => {
]
});

await setMaxItemsToRender(suggestions.length - 1);
await wrapper.setProps({ maxItemsToRender: suggestions.length - 1 });
expect(getSuggestionItemWrappers().wrappers).toHaveLength(suggestions.length - 1);

await setMaxItemsToRender(suggestions.length);
await wrapper.setProps({ maxItemsToRender: suggestions.length });
expect(getSuggestionItemWrappers().wrappers).toHaveLength(suggestions.length);

await setMaxItemsToRender(suggestions.length + 1);
await wrapper.setProps({ maxItemsToRender: suggestions.length });
expect(getSuggestionItemWrappers().wrappers).toHaveLength(suggestions.length);
});
});

interface RenderQuerySuggestionsOptions {
/** The suggestions list to render. */
suggestions?: Suggestion[];
/** The maximum number of items to render. */
maxItemsToRender?: string;
/** The template to render. */
template?: string;
}

interface RenderQuerySuggestionsApi {
/** QuerySuggestions component testing wrapper. */
wrapper: Wrapper<Vue>;
/** Retrieves the list item of each suggestion. */
getSuggestionItemWrappers: () => WrapperArray<Vue>;
/** Updates the maximum number of items to render. */
setMaxItemsToRender: (max: number) => Promise<void>;
/** Rendered suggestions data. */
suggestions: Suggestion[];
}
Loading
Loading