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(components): add filters to base-suggestions #758

Merged
merged 18 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions packages/x-components/src/__stubs__/base-suggestion-stubs.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { BooleanFilter, Facet, Suggestion } from '@empathyco/x-types';
luismmdev marked this conversation as resolved.
Show resolved Hide resolved

/**
* Creates a base suggestion with facets.
*
* @param query - Sets a query to test.
* @param key - Sets suggestion key.
* @param modelName - Sets suggestion modelName.
* @returns A base suggestion with facets.
*
* @internal
*/
export function createSuggestionWithFacets(
query: string,
key: string,
modelName: string | any
): Suggestion[] {
return [
{
facets: createSuggestionFacets(),
key: key,
query: query,
totalResults: 10,
results: [],
modelName: modelName
}
];
}

/**
* Returns an array containing Facets.
*
* @returns An array of facets.
*/
export function createSuggestionFacets(): Facet[] {
return [
{
id: 'rootCategories',
label: 'rootCategories',
modelName: 'SimpleFacet',
filters: <Array<BooleanFilter>>[
{
facetId: 'rootCategories',
id: '{!tag=rootFilter}rootCategories_60361120_64009600:"DORMIR"',
label: 'DORMIR',
selected: false,
totalResults: 60,
modelName: 'SimpleFilter'
},
{
facetId: 'rootCategories',
id: '{!tag=rootFilter}rootCategories_60361120_64009600:"SPECIAL PRICES"',
label: 'SPECIAL PRICES',
selected: false,
totalResults: 24,
modelName: 'SimpleFilter'
}
]
},
{
id: 'exampleFacet',
label: 'exampleFacet',
modelName: 'SimpleFacet',
filters: <Array<BooleanFilter>>[
{
facetId: 'exampleFacet',
id: '{!tag=exampleFacet}exampleFacet_60361120_64009600:"EXAMPLE"',
label: 'EXAMPLE',
selected: false,
totalResults: 60,
modelName: 'SimpleFilter'
}
]
}
];
}

/**
* Returns a facet with a filter.
*
* @param filterLabel - Label of the filter.
* @returns A Facet with a filter.
*/
export function createFacetWithAFilter(filterLabel = 'EXAMPLE'): Facet[] {
return [
{
id: 'exampleFacet',
label: 'exampleFacet',
modelName: 'SimpleFacet',
filters: <Array<BooleanFilter>>[
{
facetId: 'exampleFacet',
id: '{!tag=exampleFacet}exampleFacet_60361120_64009600:"EXAMPLE"',
label: filterLabel,
selected: false,
totalResults: 60,
modelName: 'SimpleFilter'
}
]
}
];
}
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { NextQuery } from '@empathyco/x-types';
* Creates a {@link @empathyco/x-types#NextQuery | next queries} stub.
*
* @param amount - Number of stubbed next queries to create.
*
* @returns Array of next queries stub.
*
* @internal
*/
export function getNextQueriesStub(amount = 3): NextQuery[] {
Expand All @@ -21,7 +19,6 @@ export function getNextQueriesStub(amount = 3): NextQuery[] {
*
* @param query - The query of the next query.
* @param nextQuery - An optional object with fields to override the next query.
*
* @returns A next query.
*/
export function createNextQueryStub(query: string, nextQuery?: Partial<NextQuery>): NextQuery {
Expand All @@ -31,6 +28,7 @@ export function createNextQueryStub(query: string, nextQuery?: Partial<NextQuery
totalResults: 10,
results: [],
modelName: 'NextQuery',
isCurated: false,
...nextQuery
};
}
Original file line number Diff line number Diff line change
@@ -1,64 +1,98 @@
import { Suggestion } from '@empathyco/x-types';
import { BooleanFilter, Facet, Suggestion } from '@empathyco/x-types';
import { mount, Wrapper } from '@vue/test-utils';
import Vue from 'vue';
import { XPlugin } from '../../../plugins/x-plugin';
import { normalizeString } from '../../../utils/normalize';
import { createSuggestionWithFacets } from '../../../__stubs__/base-suggestion-stubs.factory';
import { XEventsTypes } from '../../../wiring/events.types';
import { getDataTestSelector, installNewXPlugin } from '../../../__tests__/utils';
import { WireMetadata } from '../../../wiring/wiring.types';
import { getDataTestSelector, installNewXPlugin } from '../../../__tests__/utils';
import BaseSuggestion from '../base-suggestion.vue';

describe('testing Base Suggestion component', () => {
function renderBaseSuggestion({
query = normalizeString('(b<ebé>)'),
suggestion = createSuggestionWithFacets('(b<ebé>) lloron', 'bebe lloron', 'QuerySuggestion')[0],
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
suggestionFacets
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
}: BaseSuggestionOptions = {}): BaseSuggestionAPI {
const [, localVue] = installNewXPlugin();

const query = normalizeString('(b<ebé>)');
const suggestion: Suggestion = {
query: '(b<ebé>) lloron',
facets: [],
key: 'bebe lloron',
modelName: 'QuerySuggestion'
};
if (suggestionFacets !== undefined) {
suggestion.facets = suggestionFacets;
}

const suggestionSelectedEvents: Partial<XEventsTypes> = {
UserSelectedAQuerySuggestion: suggestion,
UserTalked: 'belt'
};
let component: Wrapper<Vue>;

beforeEach(() => {
component = mount(BaseSuggestion, {
localVue,
propsData: { query, suggestion, suggestionSelectedEvents }
});
const wrapper = mount(BaseSuggestion, {
localVue,
propsData: {
query,
suggestion,
suggestionSelectedEvents
}
});

const wireMetadataObject = expect.objectContaining<Partial<WireMetadata>>({
target: wrapper.element
});

return {
wrapper,
suggestion,
query,
localVue,
wireMetadataObject
};
}

describe('testing Base Suggestion component', () => {
it('passes the prop suggestion to the default slot', () => {
expect(component.element.textContent).toContain(suggestion.query);
const { wrapper, suggestion } = renderBaseSuggestion();

expect(wrapper.element.textContent).toContain(suggestion.query);
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
});

it('passes the prop filter to the default slot', () => {
const { wrapper, suggestion } = renderBaseSuggestion();

expect(wrapper.element.textContent).toContain(
(<BooleanFilter>suggestion.facets[0].filters[0]).label
);
});
luismmdev marked this conversation as resolved.
Show resolved Hide resolved

it('has suggestion query parts matching query passed as prop retaining accent marks', () => {
const matchingPart = component.find(getDataTestSelector('matching-part')).text();
const { wrapper, suggestion, query } = renderBaseSuggestion();
const matchingPart = wrapper.find(getDataTestSelector('matching-part')).text();

expect(normalizeString(matchingPart)).toEqual(query);
expect(suggestion.query).toContain(matchingPart);
});

it('sanitizes the matching part of the suggestion query', () => {
const matchingPartHTML = component.find(getDataTestSelector('matching-part')).element.innerHTML;
const { wrapper } = renderBaseSuggestion();
const matchingPartHTML = wrapper.find(getDataTestSelector('matching-part')).element.innerHTML;

expect(matchingPartHTML).toBe('(b&lt;ebé&gt;)');
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
});

it('does not have matched query if the query prop is empty', () => {
component.setProps({ query: '' });
const hasMatchingQuery = (component.vm as any).hasMatchingQuery;
const { wrapper } = renderBaseSuggestion({ query: '' });
const hasMatchingQuery = (wrapper.vm as any).hasMatchingQuery;

expect(hasMatchingQuery).toBe(false);
});
luismmdev marked this conversation as resolved.
Show resolved Hide resolved

it('does not have a filter label if the suggestion has no facets', () => {
const { wrapper, suggestion } = renderBaseSuggestion({ suggestionFacets: [] });
expect(wrapper.element.textContent!.trim()).toBe(suggestion.query);
});

it('emits suggestionSelectedEvent and the default events onclick', async () => {
const target = expect.objectContaining<Partial<WireMetadata>>({ target: component.element });
const { wrapper, suggestion, localVue, wireMetadataObject: target } = renderBaseSuggestion();
const spyOn = jest.spyOn(XPlugin.bus, 'emit');
component.trigger('click');
wrapper.trigger('click');

await localVue.nextTick();
luismmdev marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -67,4 +101,61 @@ describe('testing Base Suggestion component', () => {
expect(spyOn).toHaveBeenNthCalledWith(3, 'UserSelectedAQuerySuggestion', suggestion, target);
expect(spyOn).toHaveBeenNthCalledWith(4, 'UserTalked', 'belt', target);
});

it('emits UserClickedAFilter if the suggestion has a filter', async () => {
const { wrapper, wireMetadataObject: target, localVue, suggestion } = renderBaseSuggestion();
const spyOn = jest.spyOn(XPlugin.bus, 'emit');
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
wrapper.trigger('click');

await localVue.nextTick();

expect(spyOn).toHaveBeenCalledWith(
'UserClickedAFilter',
suggestion.facets[0].filters[0],
target
);
});

it('does not emit UserClickedAFilter if there is no filter', async () => {
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
const { wrapper, suggestion, localVue, wireMetadataObject: target } = renderBaseSuggestion();
luismmdev marked this conversation as resolved.
Show resolved Hide resolved
await wrapper.setProps({ suggestion: { ...suggestion, facets: [] } });
const spyOn = jest.spyOn(XPlugin.bus, 'emit');
wrapper.trigger('click');

await localVue.nextTick();

expect(spyOn).not.toHaveBeenCalledWith(
'UserClickedAFilter',
suggestion.facets[0].filters[0],
target
);
});
});

/**
* The options to render the {@link BaseSuggestion} component.
*/
interface BaseSuggestionOptions {
/** The query introduced to find the suggestion. */
query?: string;
/** The suggestion to be rendered. By default, a suggestion with facets is used. */
suggestion?: Suggestion;
/** An array with facets to overwrite the suggestion ones. */
suggestionFacets?: Facet[];
}

/**
* Test API for the {@link BaseSuggestion} component.
*/
interface BaseSuggestionAPI {
/** The wrapper for base suggestion component. */
wrapper: Wrapper<Vue>;
/** The rendered suggestion. */
suggestion: Suggestion;
/** The query introduced to find the suggestion. */
query: string;
/** The test Vue instance. */
localVue: typeof Vue;
/** Metadata object used to keep track of the events fired to the bus. */
wireMetadataObject: Partial<WireMetadata>;
}
Loading