diff --git a/eslint.config.mjs b/eslint.config.mjs index 16495c8b..2b6a5407 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -9,9 +9,28 @@ export default empathyco( }, }, { - files: ['*-icon*.vue', 'logo.vue'], + files: ['src/**/*.{ts,tsx,vue}'], rules: { - 'max-len': 'off', + // Enable the following rules progressively when the project is ready to enforce them + 'vue/no-reserved-component-names': 'off', + 'vue/valid-v-slot': 'off', + 'vue/no-deprecated-v-on-native-modifier': 'off', + 'node/prefer-global/process': 'off', + 'no-new': 'off', + 'ts/no-floating-promises': 'off', + 'ts/no-misused-promises': 'off', + 'ts/no-unsafe-member-access': 'off', + }, + }, + { + files: ['tests/**/*.{ts,tsx,vue}'], + rules: { + // Enable the following rules progressively when the project is ready to enforce them + 'ts/no-unsafe-call': 'off', + 'ts/no-unsafe-argument': 'off', + 'ts/no-unsafe-member-access': 'off', + 'ts/no-unsafe-return': 'off', + 'ts/no-namespace': 'off', }, }, ) diff --git a/src/App.vue b/src/App.vue index 2a4e86f6..6919b317 100644 --- a/src/App.vue +++ b/src/App.vue @@ -93,7 +93,7 @@ export default defineComponent({ window.InterfaceX?.search() window.wysiwyg?.setContext({ query: payload.query }) } - } catch (_) { + } catch { // No error handling } }) diff --git a/src/adapter/adapter.ts b/src/adapter/adapter.ts index e6f978aa..6dbaca3a 100644 --- a/src/adapter/adapter.ts +++ b/src/adapter/adapter.ts @@ -1,36 +1,37 @@ import type { PlatformRecommendationsRequest, PlatformResult, - PlatformSemanticQueriesRequest} from '@empathyco/x-adapter-platform'; + PlatformSemanticQueriesRequest, +} from '@empathyco/x-adapter-platform' import type { ExperienceControlsResponse, RecommendationsRequest, Result, - SemanticQueriesRequest -} from '@empathyco/x-types'; + SemanticQueriesRequest, +} from '@empathyco/x-types' import { experienceControlsResponseSchema, platformAdapter, recommendationsRequestSchema, resultSchema, - semanticQueriesRequestSchema -} from '@empathyco/x-adapter-platform'; + semanticQueriesRequestSchema, +} from '@empathyco/x-adapter-platform' -export const adapter = platformAdapter; +export const adapter = platformAdapter /* Code sample about how to extend the result mapper with more fields. */ interface EmpathyDemoPlatformResult extends PlatformResult { - description: string; - collection: string; - brand: string; + description: string + collection: string + brand: string } declare module '@empathyco/x-types' { export interface Result { - collection: string; - description: string; - brand: string; + collection: string + description: string + brand: string } } @@ -38,16 +39,16 @@ resultSchema.$override>({ description: 'description', collection: 'collection', brand: 'brand', - images: ({ __images }) => (Array.isArray(__images) ? __images.reverse() : [__images]) -}); + images: ({ __images }) => (Array.isArray(__images) ? __images.reverse() : [__images]), +}) recommendationsRequestSchema.$override< RecommendationsRequest, Partial >({ // TODO Top clicked demo endpoint breaks if it receives the scope parameter - extraParams: ({ extraParams: { scope, ...extraParams } = {} }) => extraParams -}); + extraParams: ({ extraParams: { scope, ...extraParams } = {} }) => extraParams, +}) semanticQueriesRequestSchema.$override< SemanticQueriesRequest, @@ -56,12 +57,11 @@ semanticQueriesRequestSchema.$override< extraParams: ({ extraParams }) => { return { extraParams, - filter_ids: 'NOT_ALL_WORDS,NOT_PARTIAL' - }; - } -}); + filter_ids: 'NOT_ALL_WORDS,NOT_PARTIAL', + } + }, +}) -// eslint-disable-next-line @typescript-eslint/no-unsafe-call experienceControlsResponseSchema.$override< Partial, Partial @@ -70,7 +70,7 @@ experienceControlsResponseSchema.$override< events: { SemanticQueriesConfigProvided: { maxItemsToRequest: 'controls.semanticQueries.numberOfCarousels', - resultsPerCarousel: 'controls.semanticQueries.resultsPerCarousels' - } - } -}); + resultsPerCarousel: 'controls.semanticQueries.resultsPerCarousels', + }, + }, +}) diff --git a/src/adapter/docker.adapter.ts b/src/adapter/docker.adapter.ts index f2384a79..76b83f8d 100644 --- a/src/adapter/docker.adapter.ts +++ b/src/adapter/docker.adapter.ts @@ -1,6 +1,5 @@ -import type { - PlatformAdapter} from '@empathyco/x-adapter-platform'; -import type { XComponentsAdapter } from '@empathyco/x-types'; +import type { PlatformAdapter } from '@empathyco/x-adapter-platform' +import type { XComponentsAdapter } from '@empathyco/x-types' import { experienceControlsEndpointAdapter, identifierResultsEndpointAdapter, @@ -10,8 +9,8 @@ import { recommendationsEndpointAdapter, relatedTagsEndpointAdapter, searchEndpointAdapter, - semanticQueriesEndpointAdapter -} from '@empathyco/x-adapter-platform'; + semanticQueriesEndpointAdapter, +} from '@empathyco/x-adapter-platform' /** * Mutates adapter to point to environment context. @@ -20,35 +19,35 @@ import { */ export function overrideAdapter(adapter: PlatformAdapter): void { adapter.search = searchEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('search', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('search', extraParams!), + }) adapter.popularSearches = popularSearchesEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('popularSearches', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('popularSearches', extraParams!), + }) adapter.recommendations = recommendationsEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('recommendations', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('recommendations', extraParams!), + }) adapter.nextQueries = nextQueriesEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('nextQueries', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('nextQueries', extraParams!), + }) adapter.querySuggestions = querySuggestionsEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('querySuggestions', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('querySuggestions', extraParams!), + }) adapter.relatedTags = relatedTagsEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('relatedTags', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('relatedTags', extraParams!), + }) adapter.identifierResults = identifierResultsEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('identifierResults', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('identifierResults', extraParams!), + }) adapter.semanticQueries = semanticQueriesEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('semanticQueries', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('semanticQueries', extraParams!), + }) adapter.experienceControls = experienceControlsEndpointAdapter.extends({ - endpoint: ({ extraParams }) => resolveEmpathyEndpoint('experienceControls', extraParams!) - }); + endpoint: ({ extraParams }) => resolveEmpathyEndpoint('experienceControls', extraParams!), + }) } -type DockerEndpoints = Exclude; +type DockerEndpoints = Exclude /** * Function that returns the url for each empathy's endpoints according to the environment context. @@ -60,9 +59,9 @@ type DockerEndpoints = Exclude; * @returns The url for the given endpoint. */ function resolveEmpathyEndpoint(endpoint: DockerEndpoints, context: Record): string { - const { empathyAPIHost } = context; - const endpointHost: string = empathyAPIHost || 'localhost:8080'; - const endpointInstance = 'imdb'; + const { empathyAPIHost } = context + const endpointHost = (empathyAPIHost as string) || 'localhost:8080' + const endpointInstance = 'imdb' const empathyEndpoints: Record = { search: `http://${endpointHost}/query/${endpointInstance}/search`, popularSearches: `http://${endpointHost}/query/${endpointInstance}/empathize`, @@ -73,7 +72,7 @@ function resolveEmpathyEndpoint(endpoint: DockerEndpoints, context: Record diff --git a/src/composables/use-has-scroll-past-threshold.composable.ts b/src/composables/use-has-scroll-past-threshold.composable.ts index 4638ddb8..ef3ad501 100644 --- a/src/composables/use-has-scroll-past-threshold.composable.ts +++ b/src/composables/use-has-scroll-past-threshold.composable.ts @@ -1,34 +1,37 @@ -import type { Ref } from 'vue'; -import { useState } from '@empathyco/x-components'; -import { computed, ref, watch } from 'vue'; +import type { ScrollComponentState } from '@empathyco/x-components/types' +import type { Ref } from 'vue' +import { useState } from '@empathyco/x-components' +import { computed, ref, watch } from 'vue' export const useHasScrollPastThreshold = (): { hasScrolledPastThreshold: Ref } => { - const hasScrolledPastThresholdFlag = ref(false); - const scrollOffset = 100; - const { data: scrollPositionsMap } = useState('scroll', ['data']); - const mainScrollPosition = computed(() => scrollPositionsMap.value['main-scroll']?.position); + const hasScrolledPastThresholdFlag = ref(false) + const scrollOffset = 100 + const { data: scrollPositionsMap } = useState('scroll', ['data']) + const mainScrollPosition = computed( + () => scrollPositionsMap.value['main-scroll']?.position as number, + ) - const hasScrolledPastThreshold = computed(() => hasScrolledPastThresholdFlag.value); + const hasScrolledPastThreshold = computed(() => hasScrolledPastThresholdFlag.value) watch(mainScrollPosition, () => { - const mainScrollData = scrollPositionsMap.value['main-scroll']; + const mainScrollData = scrollPositionsMap.value['main-scroll'] as ScrollComponentState if (mainScrollData?.hasReachedStart) { - hasScrolledPastThresholdFlag.value = false; - return; + hasScrolledPastThresholdFlag.value = false + return } else { - hasScrolledPastThresholdFlag.value = true; + hasScrolledPastThresholdFlag.value = true } - const isScrollingUp = mainScrollData?.direction === 'UP'; + const isScrollingUp = mainScrollData?.direction === 'UP' if (isScrollingUp || mainScrollPosition.value < scrollOffset) { - hasScrolledPastThresholdFlag.value = false; + hasScrolledPastThresholdFlag.value = false } else if (!isScrollingUp && mainScrollPosition.value > scrollOffset) { - hasScrolledPastThresholdFlag.value = true; + hasScrolledPastThresholdFlag.value = true } - }); + }) return { - hasScrolledPastThreshold - }; -}; + hasScrolledPastThreshold, + } +} diff --git a/src/i18n/messages/index.ts b/src/i18n/messages/index.ts index 018e68b4..5fbe7078 100644 --- a/src/i18n/messages/index.ts +++ b/src/i18n/messages/index.ts @@ -14,11 +14,9 @@ // export { default as es } from './es.messages.json'; // Example of how to make the spanish messages be lazy loaded, only when the locale is set to `es` -/* eslint-disable @typescript-eslint/explicit-function-return-type */ -export const de = async () => import('./de.messages.json'); -export const es = async () => import('./es.messages.json'); -export const en = async () => import('./en.messages.json'); -export const fr = async () => import('./fr.messages.json'); -export const pt = async () => import('./pt.messages.json'); -export const it = async () => import('./it.messages.json'); -/* eslint-enable @typescript-eslint/explicit-function-return-type */ +export const de = async () => import('./de.messages.json') +export const es = async () => import('./es.messages.json') +export const en = async () => import('./en.messages.json') +export const fr = async () => import('./fr.messages.json') +export const pt = async () => import('./pt.messages.json') +export const it = async () => import('./it.messages.json') diff --git a/src/main.ts b/src/main.ts index c543e1bd..ffc4868e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,24 +1,24 @@ -import { CssInjector } from '@empathyco/x-archetype-utils'; -import { XInstaller } from '@empathyco/x-components'; -import { getInstallXOptions } from './x-components/plugin.options'; +import { CssInjector } from '@empathyco/x-archetype-utils' +import { XInstaller } from '@empathyco/x-components' +import { getInstallXOptions } from './x-components/plugin.options' declare global { interface Window { - __enableVueDevtools__?: boolean; + __enableVueDevtools__?: boolean wysiwyg?: { - goToLogin: () => Promise; - requestAuth: () => Promise; - open: () => Promise; - close: () => Promise; + goToLogin: () => Promise + requestAuth: () => Promise + open: () => Promise + close: () => Promise setContext: ( newContext: Partial<{ - query: string | undefined; - spellcheckedQuery: string | undefined; - }> - ) => void; - }; + query: string | undefined + spellcheckedQuery: string | undefined + }>, + ) => void + } } } -new CssInjector(true); -getInstallXOptions().then(async installXOptions => new XInstaller(installXOptions).init()); +new CssInjector(true) +getInstallXOptions().then(async installXOptions => new XInstaller(installXOptions).init()) diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts index 64c3fd9e..a99cf76c 100644 --- a/src/shims-vue.d.ts +++ b/src/shims-vue.d.ts @@ -1,5 +1,5 @@ declare module '*.vue' { - import type { DefineComponent } from 'vue'; - const component: DefineComponent<{}, {}, any>; - export default component; + import type { DefineComponent } from 'vue' + const component: DefineComponent + export default component } diff --git a/src/x-components/plugin.options.ts b/src/x-components/plugin.options.ts index ea752e04..6709a5e0 100644 --- a/src/x-components/plugin.options.ts +++ b/src/x-components/plugin.options.ts @@ -1,32 +1,32 @@ -import type { InstallXOptions, SnippetConfig } from '@empathyco/x-components'; -import { cssInjector, I18n } from '@empathyco/x-archetype-utils'; -import { filter } from '@empathyco/x-components'; -import { addQueryToHistoryQueries } from '@empathyco/x-components/history-queries'; -import { setSearchQuery } from '@empathyco/x-components/search'; -import { setUrlQuery } from '@empathyco/x-components/url'; -import { adapter } from '../adapter/adapter'; -import { default as AppComponent } from '../App.vue'; -import { useDevice } from '../composables/use-device.composable'; -import * as messages from '../i18n/messages'; -import store from '../store'; -import { mergeSemanticQueriesConfigWire } from './wiring/semantic-queries.wiring'; +import type { InstallXOptions, SnippetConfig } from '@empathyco/x-components' +import { cssInjector, I18n } from '@empathyco/x-archetype-utils' +import { filter } from '@empathyco/x-components' +import { addQueryToHistoryQueries } from '@empathyco/x-components/history-queries' +import { setSearchQuery } from '@empathyco/x-components/search' +import { setUrlQuery } from '@empathyco/x-components/url' +import { adapter } from '../adapter/adapter' +import AppComponent from '../App.vue' +import { useDevice } from '../composables/use-device.composable' +import * as messages from '../i18n/messages' +import store from '../store' +import { mergeSemanticQueriesConfigWire } from './wiring/semantic-queries.wiring' -const device = useDevice(); +const device = useDevice() const setSearchQueryFiltered = filter( setSearchQuery, - ({ eventPayload }) => !eventPayload.startsWith('::') -); + ({ eventPayload }) => !eventPayload.startsWith('::'), +) const addQueryToHistoryQueriesFiltered = filter( addQueryToHistoryQueries, - ({ eventPayload }) => !eventPayload.startsWith('::') -); + ({ eventPayload }) => !eventPayload.startsWith('::'), +) const setUrlQueryFiltered = filter( setUrlQuery, - ({ eventPayload }) => !eventPayload.startsWith('::') -); + ({ eventPayload }) => !eventPayload.startsWith('::'), +) /** * Function that returns the options to install x-components. @@ -35,22 +35,22 @@ const setUrlQueryFiltered = filter( */ export async function getInstallXOptions(): Promise { if (process.env.VUE_APP_DEVELOPMENT_DOCKER) { - const { overrideAdapter } = await import('../adapter/docker.adapter'); - overrideAdapter(adapter); - (window.initX as SnippetConfig).queriesPreview = [ + const { overrideAdapter } = await import('../adapter/docker.adapter') + overrideAdapter(adapter) + ;(window.initX as SnippetConfig).queriesPreview = [ { query: 'short', - title: 'Short' + title: 'Short', }, { query: 'comedy', - title: 'Comedy' + title: 'Comedy', }, { query: 'family', - title: 'Family' - } - ]; + title: 'Family', + }, + ] } return { adapter, @@ -60,59 +60,59 @@ export async function getInstallXOptions(): Promise { xModules: { facets: { config: { - filtersStrategyForRequest: 'leaves-only' - } + filtersStrategyForRequest: 'leaves-only', + }, }, semanticQueries: { config: { threshold: 50, - maxItemsToRequest: 10 + maxItemsToRequest: 10, }, wiring: { SemanticQueriesConfigProvided: { - mergeSemanticQueriesConfigWire - } - } + mergeSemanticQueriesConfigWire, + }, + }, }, search: { wiring: { UserAcceptedAQuery: { - setSearchQuery: setSearchQueryFiltered - } - } + setSearchQuery: setSearchQueryFiltered, + }, + }, }, historyQueries: { wiring: { UserAcceptedAQuery: { - addQueryToHistoryQueries: addQueryToHistoryQueriesFiltered - } - } + addQueryToHistoryQueries: addQueryToHistoryQueriesFiltered, + }, + }, }, url: { wiring: { UserAcceptedAQuery: { - setUrlQuery: setUrlQueryFiltered - } - } - } + setUrlQuery: setUrlQueryFiltered, + }, + }, + }, }, async installExtraPlugins({ app, snippet }) { const i18n = await I18n.create({ locale: snippet.uiLang, device: (snippet.device as string) ?? device.deviceName.value, fallbackLocale: 'en', - messages - }); + messages, + }) - app.use(i18n); - app.config.globalProperties.$setLocale = i18n.setLocale.bind(i18n); - app.config.globalProperties.$setLocaleDevice = i18n.setDevice.bind(i18n); + app.use(i18n) + app.config.globalProperties.$setLocale = i18n.setLocale.bind(i18n) + app.config.globalProperties.$setLocaleDevice = i18n.setDevice.bind(i18n) return { - i18n: i18n.vueI18n - }; - } - }; + i18n: i18n.vueI18n, + } + }, + } } /** @@ -122,19 +122,19 @@ export async function getInstallXOptions(): Promise { * @returns The DOM element. */ function getDomElement({ isolate }: SnippetConfig): Element { - const container = document.createElement('div'); - container.classList.add('x-root-container'); - const domElement = document.createElement('div'); + const container = document.createElement('div') + container.classList.add('x-root-container') + const domElement = document.createElement('div') if (isolate || process.env.NODE_ENV === 'production') { - const shadowRoot = container.attachShadow({ mode: 'open' }); - shadowRoot.appendChild(domElement); - cssInjector.setHost(shadowRoot); + const shadowRoot = container.attachShadow({ mode: 'open' }) + shadowRoot.appendChild(domElement) + cssInjector.setHost(shadowRoot) } else { - container.appendChild(domElement); - cssInjector.setHost(document.head); + container.appendChild(domElement) + cssInjector.setHost(document.head) } - document.body.appendChild(container); - return domElement; + document.body.appendChild(container) + return domElement } diff --git a/tests/e2e/cucumber/common-steps.spec.ts b/tests/e2e/cucumber/common-steps.spec.ts index 35ddc0d7..e78358a6 100644 --- a/tests/e2e/cucumber/common-steps.spec.ts +++ b/tests/e2e/cucumber/common-steps.spec.ts @@ -1,87 +1,86 @@ -import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'; -import ViewportPreset = Cypress.ViewportPreset; +import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor' +import ViewportPreset = Cypress.ViewportPreset Given('start page with {string} size view', (view: ViewportPreset) => { - cy.viewport(view); - cy.visit('/'); -}); + cy.viewport(view) + cy.visit('/') +}) Then('search bar is clicked', () => { - cy.getByDataTest('x').should('exist'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - cy.window().then(window => (window as any).InterfaceX.search()); -}); + cy.getByDataTest('x').should('exist') + cy.window().then(window => window.InterfaceX.search()) +}) // Search When('a {string} is typed', (query: string) => { - cy.getByDataTest('search-input').should('exist').click(); + cy.getByDataTest('search-input').should('exist').click() cy.typeQuery(query).then(() => { - cy.getByDataTest('search-input').invoke('val').as('searchedQuery'); - }); -}); + cy.getByDataTest('search-input').invoke('val').as('searchedQuery') + }) +}) When('{string} is searched', (query: string) => { - cy.getByDataTest('search-input').should('exist').click(); + cy.getByDataTest('search-input').should('exist').click() cy.searchQuery(query).then(() => { - cy.getByDataTest('search-input').invoke('val').as('searchedQuery'); - }); -}); + cy.getByDataTest('search-input').invoke('val').as('searchedQuery') + }) +}) Given('a {string} of queries already searched', (list: string) => { - cy.searchQueries(...list.split(', ')); -}); + cy.searchQueries(...list.split(', ')) +}) When('search input is cleared', () => { - cy.clearSearchInput(); -}); + cy.clearSearchInput() +}) // Facets When('facets are shown if hidden on {string}', (view: ViewportPreset) => { if (!view.includes('macbook')) { - cy.getByDataTest('open-modal-id').click(); + cy.getByDataTest('open-modal-id').click() } -}); +}) When('facets are hidden if shown on {string}', (view: ViewportPreset) => { if (!view.includes('macbook')) { - cy.getByDataTest('close-modal-id').click(); + cy.getByDataTest('close-modal-id').click() } -}); +}) // Navigation When('navigating back', () => { - cy.go('back'); -}); + cy.go('back') +}) // Requests Then('a search request from {string} is done', (origin: string) => { - cy.wait(`@interceptedResultsFrom:${origin}`); -}); + cy.wait(`@interceptedResultsFrom:${origin}`) +}) // Results Then('related results are displayed', () => { - cy.getByDataTest('search-grid-result').eq(0).scrollIntoView(); + cy.getByDataTest('search-grid-result').eq(0).scrollIntoView() cy.getByDataTest('search-grid-result') .should('be.visible') .should('have.length.at.least', 1) .invoke('text') - .as('resultsList'); -}); + .as('resultsList') +}) Then('related results have changed', () => { - cy.getByDataTest('search-grid-result').first().scrollIntoView(); + cy.getByDataTest('search-grid-result').first().scrollIntoView() cy.get('@resultsList').then(resultsList => { cy.getByDataTest('search-grid-result') .should('be.visible') .should('have.length.at.least', 1) .should(newResultsList => { - expect(newResultsList.text()).to.be.not.equal(resultsList); + expect(newResultsList.text()).to.be.not.equal(resultsList) }) .invoke('text') - .as('resultsList'); - }); -}); + .as('resultsList') + }) +}) Then('subheader is not visible', () => { - cy.getByDataTest('sub-header').should('not.be.visible'); -}); + cy.getByDataTest('sub-header').should('not.be.visible') +}) diff --git a/tests/e2e/cucumber/facets.spec.ts b/tests/e2e/cucumber/facets.spec.ts index f8578e9c..4af3295b 100644 --- a/tests/e2e/cucumber/facets.spec.ts +++ b/tests/e2e/cucumber/facets.spec.ts @@ -1,5 +1,5 @@ -import { Then, When } from '@badeball/cypress-cucumber-preprocessor'; -import '../cucumber/global-definitions'; +import { Then, When } from '@badeball/cypress-cucumber-preprocessor' +import '../cucumber/global-definitions' /** * TODO https://searchbroker.atlassian.net/browse/EX-5266 . @@ -9,16 +9,16 @@ import '../cucumber/global-definitions'; // Scenario 1 Then('facets are displayed is {boolean}', (areVisible: boolean) => { - cy.getByDataTest('facets-facet').should(`${areVisible ? '' : 'not.'}exist`); -}); + cy.getByDataTest('facets-facet').should(`${areVisible ? '' : 'not.'}exist`) +}) When('sort and filter button is clicked on {string}', () => { - cy.getByDataTest('toggle-facets-button').click({ force: true }); -}); + cy.getByDataTest('toggle-facets-button').click({ force: true }) +}) When('{string} is clicked to close the modal', (closeMethod: string) => { - cy.getByDataTest(closeMethod).eq(0).click('topLeft', { force: true }); -}); + cy.getByDataTest(closeMethod).eq(0).click('topLeft', { force: true }) +}) // Scenario 2 When('filter {int} from facet {string} is clicked', (filterNumber: number, facetName: string) => { cy.getByDataTest(facetName) @@ -26,28 +26,27 @@ When('filter {int} from facet {string} is clicked', (filterNumber: number, facet .eq(filterNumber) .click() .invoke('text') - .as(`clickedFilter${filterNumber}`); -}); + .as(`clickedFilter${filterNumber}`) +}) Then( 'filter {int} from facet {string} is selected is {boolean}', function (this: any, filterNumber: number, facetName: string, isSelected: boolean) { cy.getByDataTest(facetName) - // eslint-disable-next-line @typescript-eslint/no-unsafe-call .contains(this[`clickedFilter${filterNumber}`].trim()) .should(`${isSelected ? '' : 'not.'}to.have.class`, 'x-selected') - .should('have.attr', 'aria-checked'); - } -); + .should('have.attr', 'aria-checked') + }, +) When('clear filters button is clicked', () => { - cy.getByDataTest('clear-filters').click(); -}); + cy.getByDataTest('clear-filters').click() +}) // Scenario 4 When('facet {string} is unfolded', (facetName: string) => { - cy.getByDataTest(facetName).getByDataTest('toggle-panel-header').click(); -}); + cy.getByDataTest(facetName).getByDataTest('toggle-panel-header').click() +}) // Scenario 5 When( @@ -61,9 +60,9 @@ When( .eq(childFilterIndex) .click() .invoke('text') - .as(`clickedChildFilter${childFilterIndex}`); - } -); + .as(`clickedChildFilter${childFilterIndex}`) + }, +) Then( 'selection status of child filter {int} from parent filter {int} in facet {string} is {boolean}', @@ -72,7 +71,7 @@ Then( childFilterIndex: number, hierarchicalFilterIndex: number, facetName: string, - isSelected: boolean + isSelected: boolean, ) { cy.getByDataTest(facetName) .getByDataTest('base-filters-item') @@ -80,12 +79,11 @@ Then( .getByDataTest('children-filters') .getByDataTest('filter') .eq(childFilterIndex) - // eslint-disable-next-line @typescript-eslint/no-unsafe-call .should('contain', this[`clickedChildFilter${childFilterIndex}`].replace(/[^a-z]/gi, '')) .should(`${isSelected ? '' : 'not.'}to.have.class`, 'x-selected') - .should('have.attr', 'aria-checked'); - } -); + .should('have.attr', 'aria-checked') + }, +) Then( 'selection status of filter number {int} in facet {string} is {boolean}', @@ -94,6 +92,6 @@ Then( .getByDataTest('base-filters-item') .eq(hierarchicalFilterIndex) .getByDataTest('filter') - .should(`${isSelected ? '' : 'not.'}to.have.class`, 'x-selected'); - } -); + .should(`${isSelected ? '' : 'not.'}to.have.class`, 'x-selected') + }, +) diff --git a/tests/e2e/support/index.ts b/tests/e2e/support/index.ts index bd05d014..5eb872ed 100644 --- a/tests/e2e/support/index.ts +++ b/tests/e2e/support/index.ts @@ -1,13 +1,12 @@ -import type { AnyFunction} from '@empathyco/x-utils'; -import { forEach } from '@empathyco/x-utils'; +import type { AnyFunction } from '@empathyco/x-utils' +import { forEach } from '@empathyco/x-utils' -import Loggable = Cypress.Loggable; -import Shadow = Cypress.Shadow; -import Timeoutable = Cypress.Timeoutable; -import Withinable = Cypress.Withinable; +import Loggable = Cypress.Loggable +import Shadow = Cypress.Shadow +import Timeoutable = Cypress.Timeoutable +import Withinable = Cypress.Withinable declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace namespace Cypress { interface Chainable extends CustomCommands, CustomDualCommands {} } @@ -21,10 +20,7 @@ declare global { * https://github.com/cypress-io/cypress/issues/8418. * Https://github.com/cypress-io/cypress/issues/22129. */ -Cypress.on( - 'uncaught:exception', - err => !err.message.includes('ResizeObserver loop limit exceeded') -); +Cypress.on('uncaught:exception', err => !err.message.includes('ResizeObserver loop limit exceeded')) interface CustomCommands { /** @@ -37,7 +33,7 @@ interface CustomCommands { * @returns A Chainable object. * @internal */ - searchQuery: (query: string) => Cypress.Chainable; + searchQuery: (query: string) => Cypress.Chainable /** * Searches multiple queries by typing it in the search input and pressing enter. * @@ -47,7 +43,7 @@ interface CustomCommands { * @param queries - The query to search. * @returns A Chainable object. */ - searchQueries: (...queries: string[]) => void; + searchQueries: (...queries: string[]) => void /** * Types a query into the search input. * @@ -58,7 +54,7 @@ interface CustomCommands { * @returns A Chainable object. * @internal */ - typeQuery: (query: string) => Cypress.Chainable; + typeQuery: (query: string) => Cypress.Chainable /** * Focus into the search input. * @@ -67,7 +63,7 @@ interface CustomCommands { * * @returns A Chainable object. */ - focusSearchInput: () => Cypress.Chainable; + focusSearchInput: () => Cypress.Chainable /** * Clear search input. * @@ -76,7 +72,7 @@ interface CustomCommands { * * @returns A Chainable object. */ - clearSearchInput: () => Cypress.Chainable; + clearSearchInput: () => Cypress.Chainable } interface CustomDualCommands { /** @@ -89,43 +85,43 @@ interface CustomDualCommands { * @param options - The options passed to the Cypress command. * @returns A Chainable object. */ - getByDataTest: (value: string, options?: CypressCommandOptions) => Cypress.Chainable; + getByDataTest: (value: string, options?: CypressCommandOptions) => Cypress.Chainable } type AddPreviousParam> = { [Key in keyof Functions]: ( previous: unknown, ...args: Parameters - ) => ReturnType; -}; + ) => ReturnType +} -type CypressCommandOptions = Partial; +type CypressCommandOptions = Partial const customCommands: CustomCommands = { searchQuery: query => cy.typeQuery(query).type('{enter}', { force: true }), searchQueries: (...queries) => { queries.forEach(query => { - cy.getByDataTest('search-input').clear({ force: true }); - cy.typeQuery(query).type('{enter}', { force: true }); - }); + cy.getByDataTest('search-input').clear({ force: true }) + cy.typeQuery(query).type('{enter}', { force: true }) + }) }, typeQuery: query => cy.getByDataTest('search-input').type(query, { force: true }), focusSearchInput: () => cy.getByDataTest('search-input').click(), - clearSearchInput: () => cy.getByDataTest('clear-search-input').click() -}; + clearSearchInput: () => cy.getByDataTest('clear-search-input').click(), +} const customDualCommands: AddPreviousParam = { getByDataTest: (previous, value, options?: CypressCommandOptions) => { - const selector = `[data-test=${value}]`; - return previous ? cy.wrap(previous).find(selector, options) : cy.get(selector, options); - } -}; + const selector = `[data-test=${value}]` + return previous ? cy.wrap(previous).find(selector, options) : cy.get(selector, options) + }, +} // Register the commands forEach(customCommands, (name, implementation) => { - Cypress.Commands.add(name, implementation); -}); + Cypress.Commands.add(name, implementation) +}) forEach(customDualCommands, (name, implementation) => { - Cypress.Commands.add(name, { prevSubject: 'optional' }, implementation); -}); + Cypress.Commands.add(name, { prevSubject: 'optional' }, implementation) +})