diff --git a/packages/x-components/src/__stubs__/banners-stubs.factory.ts b/packages/x-components/src/__stubs__/banners-stubs.factory.ts index 29c557e640..29682d1c4d 100644 --- a/packages/x-components/src/__stubs__/banners-stubs.factory.ts +++ b/packages/x-components/src/__stubs__/banners-stubs.factory.ts @@ -9,38 +9,35 @@ import { Banner } from '@empathyco/x-types'; */ export function getBannersStub(): Banner[] { return [ - createBannerStub('1', 1), - createBannerStub('2', 3), - createBannerStub('3', 3), - createBannerStub('4', 4), - createBannerStub('5', 7), - createBannerStub('6', 9) + createBannerStub('1', { position: 1 }), + createBannerStub('2', { position: 3 }), + createBannerStub('3', { position: 3 }), + createBannerStub('4', { position: 4 }), + createBannerStub('5', { position: 7 }), + createBannerStub('6', { position: 9 }) ]; } /** - * Creates a banner with a "unique" identifier. + * Creates a banner. * * @param identifier - The banner identifier. - * @param position - The banner position (= row) inside the grid. - * + * @param banner - An optional object with fields to override the banner. * @returns The banner. * * @internal */ -export function createBannerStub(identifier: string, position?: number): Banner { +export function createBannerStub(identifier: string, banner?: Partial): Banner { return { id: `xb-${identifier}`, - title: `Banner ${identifier}`, - url: `/banner/${identifier}`, image: `xb-${identifier}.jpg`, - position, + modelName: 'Banner', tagging: { click: { params: {}, url: '' } }, - modelName: 'Banner' + ...banner }; } diff --git a/packages/x-components/src/components/__tests__/items-list.spec.ts b/packages/x-components/src/components/__tests__/items-list.spec.ts index 49e856a13e..c38d5ded80 100644 --- a/packages/x-components/src/components/__tests__/items-list.spec.ts +++ b/packages/x-components/src/components/__tests__/items-list.spec.ts @@ -76,7 +76,7 @@ describe('testing ItemsList component', () => { const { wrapper } = renderItemsList({ scopedSlots: { result: ``, - banner: ``, + banner: ``, promoted: `` }, items: [resultsStub[0], promotedsStub[0], bannersStub[0]] @@ -87,7 +87,7 @@ describe('testing ItemsList component', () => { ); expect(wrapper.find(getDataTestSelector('banners-list-item')).text()).toBe( - `Banner: ${bannersStub[0].title}` + `Banner: ${bannersStub[0].id}` ); expect(wrapper.find(getDataTestSelector('promoteds-list-item')).text()).toBe( diff --git a/packages/x-components/src/x-modules/search/components/__tests__/banner.spec.ts b/packages/x-components/src/x-modules/search/components/__tests__/banner.spec.ts index da83456ab8..aff86af52c 100644 --- a/packages/x-components/src/x-modules/search/components/__tests__/banner.spec.ts +++ b/packages/x-components/src/x-modules/search/components/__tests__/banner.spec.ts @@ -44,28 +44,26 @@ describe('testing Banner component', () => { expect(getXComponentXModuleName(wrapper.vm)).toEqual('search'); }); - it('renders the banner component', () => { + it('renders a banner component with title', () => { const { wrapper } = renderBanner({ - banner: { - modelName: 'Banner', - id: '12345', - url: 'https://empathy.co', - title: 'Search UIs', - image: 'https://empathy.co/x-components.jpg', - position: 1, - tagging: { - click: { url: 'https://track-things.com', params: {} } - } - } + banner: createBannerStub('banner', { title: 'Search UIs' }) }); expect(wrapper.get(getDataTestSelector('banner')).text()).toEqual('Search UIs'); }); + it('renders a banner component without title', () => { + const { wrapper } = renderBanner({ + banner: createBannerStub('banner') + }); + + expect(wrapper.get(getDataTestSelector('banner')).text()).toEqual(''); + }); + // eslint-disable-next-line max-len - it('emits UserClickedABanner when the user clicks in the left, middle or right button on the component', () => { + it('renders a banner which emits UserClickedABanner when the user clicks in the left, middle or right button on the component', () => { const listener = jest.fn(); - const banner = createBannerStub('banner'); + const banner = createBannerStub('banner', { url: 'https://empathy.co' }); const { wrapper } = renderBanner({ banner }); wrapper.vm.$x.on('UserClickedABanner').subscribe(listener); @@ -80,6 +78,25 @@ describe('testing Banner component', () => { expect(listener).toHaveBeenCalledTimes(3); }); + + it('renders a banner which does not emits any event on click', () => { + const listener = jest.fn(); + const { wrapper } = renderBanner({ + banner: createBannerStub('banner', { title: 'Search UIs' }) + }); + wrapper.vm.$x.on('UserClickedABanner').subscribe(listener); + + wrapper.trigger('click'); + expect(listener).not.toHaveBeenCalled(); + + wrapper.trigger('click', { button: 1 }); + expect(listener).not.toHaveBeenCalled(); + + wrapper.trigger('click', { button: 2 }); + expect(listener).not.toHaveBeenCalled(); + + expect(listener).toHaveBeenCalledTimes(0); + }); }); interface RenderBannerOptions { diff --git a/packages/x-components/src/x-modules/search/components/__tests__/banners-list.spec.ts b/packages/x-components/src/x-modules/search/components/__tests__/banners-list.spec.ts index 89a63a8505..858e74acff 100644 --- a/packages/x-components/src/x-modules/search/components/__tests__/banners-list.spec.ts +++ b/packages/x-components/src/x-modules/search/components/__tests__/banners-list.spec.ts @@ -90,7 +90,7 @@ describe('testing BannersList component', () => { template: ` ` }); @@ -98,7 +98,7 @@ describe('testing BannersList component', () => { expect(wrapper.classes('x-items-list')).toBe(true); expect(wrapper.find(getDataTestSelector('banners-list-item')).exists()).toBe(true); expect(wrapper.find(getDataTestSelector('banner-slot-overridden')).text()).toBe( - `Custom banner: ${getBanners()[0].title}` + `Custom banner: ${getBanners()[0].id}` ); }); diff --git a/packages/x-components/src/x-modules/search/components/banner.vue b/packages/x-components/src/x-modules/search/components/banner.vue index 47ba787b2e..ef723e42b5 100644 --- a/packages/x-components/src/x-modules/search/components/banner.vue +++ b/packages/x-components/src/x-modules/search/components/banner.vue @@ -1,15 +1,23 @@ diff --git a/packages/x-components/tests/e2e/common/mocked-responses.spec.ts b/packages/x-components/tests/e2e/common/mocked-responses.spec.ts index 159a07860d..08095ef24f 100644 --- a/packages/x-components/tests/e2e/common/mocked-responses.spec.ts +++ b/packages/x-components/tests/e2e/common/mocked-responses.spec.ts @@ -323,7 +323,17 @@ Given('a results API with a promoted', () => { Given('a results API with a banner', () => { cy.intercept(searchEndpoint, req => { - req.reply(createSearchResponse({ banners: [createBannerStub('Banner')] })); + req.reply( + createSearchResponse({ + banners: [ + createBannerStub('Banner', { + title: 'Banner', + url: '/banner/Banner', + image: '/img/test-image-1.jpeg' + }) + ] + }) + ); }).as('interceptedResults'); }); diff --git a/packages/x-components/tests/unit/banner.spec.ts b/packages/x-components/tests/unit/banner.spec.ts new file mode 100644 index 0000000000..5c6d396033 --- /dev/null +++ b/packages/x-components/tests/unit/banner.spec.ts @@ -0,0 +1,89 @@ +import { mount } from 'cypress/vue2'; +import { Banner as BannerModel } from '@empathyco/x-types'; +import Banner from '../../src/x-modules/search/components/banner.vue'; +import { createBannerStub } from '../../src/__stubs__/index'; + +/** + * Mounts a {@link Banner} component with the provided options. + * + * @param options - The options to render the component with. + * @returns An API to test the component. + */ +function mountBanner({ + banner, + template = ` +
+ +
+ ` +}: MountBannerOptions): MountBannerAPI { + cy.viewport(1920, 200); + mount({ + components: { + Banner + }, + data() { + return { + banner + }; + }, + template + }); + + return { + getBanner() { + return cy.getByDataTest('banner'); + }, + getBannerImage() { + return cy.getByDataTest('banner-image'); + } + }; +} + +describe('testing Banner component', () => { + it('banner renders if the image loads', () => { + const { getBanner, getBannerImage } = mountBanner({ + banner: createBannerStub('banner', { + title: 'Search UIs', + url: 'https://empathy.co', + position: 1, + image: '/img/test-image-1.jpeg' + }) + }); + // Loading + getBanner().should('exist'); + getBannerImage().should('exist'); + + // Success + getBanner().should('exist'); + getBannerImage().should('exist'); + }); + + it('banner is not rendered if image load fails', () => { + const { getBanner, getBannerImage } = mountBanner({ + banner: createBannerStub('banner', { + title: 'Search UIs', + url: 'https://empathy.co', + position: 1 + }) + }); + // Loading + getBanner().should('exist'); + getBannerImage().should('exist'); + + // Error + getBanner().should('not.exist'); + }); +}); + +interface MountBannerOptions { + /** The banner data. */ + banner?: BannerModel; + /** The template to be rendered. */ + template?: string; +} + +interface MountBannerAPI { + getBanner: () => Cypress.Chainable; + getBannerImage: () => Cypress.Chainable; +} diff --git a/packages/x-types/src/banner.model.ts b/packages/x-types/src/banner.model.ts index 8b22e3bb24..564b4c3062 100644 --- a/packages/x-types/src/banner.model.ts +++ b/packages/x-types/src/banner.model.ts @@ -11,9 +11,9 @@ import { Taggable } from './tagging.model'; */ export interface Banner extends NamedModel<'Banner'>, Identifiable, Taggable { /** Banner title. */ - title: string; + title?: string; /** URL to redirect. */ - url: string; + url?: string; /** Banner image. */ image: string; /** Banner position (= row) inside the grid. */