UNPKG

@benshi.ai/js-sdk

Version:

Benshi SDK

710 lines (551 loc) 25.1 kB
/** * @jest-environment jsdom */ import BsCore from "../../../core/BsCore" import CatalogRepository from "../../../core/repositories/catalog/CatalogRepository"; import ECommerce from "../../ECommerce"; import { DeliveryAction, ECommerceTypes } from "../../ECommerce/typings"; import Navigation from ".." import { AppAction, AudioVideoType, ContentBlock, IdentifyAction, ImageType, MediaActionForImage, MediaActionForVideo, NavigationTypes, NudgeAction, NudgeResponseType, RateType, TrackActions, TrackTypes, UserInfo, } from "../typings"; import { ItemType } from "../../ECommerce/typings"; let windowSpy let mockSender; class MockImpressionsDetector { start() { } stop() { } restart() { } } describe('Navigation', () => { beforeEach(() => { mockSender = { add() { return false } } windowSpy = jest.spyOn(window, "window", "get"); }) afterEach(() => { // to remove the singleton instance (BsCore as any).instance = null }) describe('Identification', () => { it('Should deliver events with deviceId instead of userId before identification', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) Navigation.logPageEvent({ path: '/mypath', title: 'page-title' }) expect(senderSpy).toBeCalledWith( expect.stringMatching(DEFAULT_DEVICE_ID), expect.anything(), expect.anything(), expect.anything()) }) it('Should deliver events with userId once the user has been logged', () => { const DEFAULT_USER_ID = 'dummy_user' const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) bsCore.login(DEFAULT_USER_ID) Navigation.logPageEvent({ path: '/mypath', title: 'page-title' }) expect(senderSpy).toBeCalledWith( expect.stringMatching(DEFAULT_USER_ID), expect.anything(), expect.anything(), expect.anything()) }) it('Should stop using user_id after logout', () => { const DEFAULT_USER_ID = 'dummy_user' const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) bsCore.login(DEFAULT_USER_ID) Navigation.logPageEvent({ path: '/mypath', title: 'page-title' }) bsCore.logout() Navigation.logPageEvent({ path: '/mypath', title: 'page-title' }) expect(senderSpy).toBeCalledWith( expect.stringMatching(DEFAULT_USER_ID), expect.anything(), expect.anything(), expect.anything()) }) }) describe('Navigation', () => { it('Should deliver an "App" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { action: AppAction.Background, start_time: 0 } Navigation.logAppEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.App, props: event }), expect.anything()) }) it('Should deliver a "Media" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { type: ImageType.Image, id: 'id-media-event', action: MediaActionForImage.Play, } const sentEvent = { type: ImageType.Image, time: 0, id_source: 'id-media-event', id: 'image_id-media-event', action: MediaActionForImage.Play, } Navigation.logMediaEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Media, props: sentEvent }), expect.anything()) }) it('Should deliver a "Media" event with default type', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { type: ImageType.Image, id: 'id-media-event', action: MediaActionForImage.Play, } Navigation.logMediaEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { block: ContentBlock.Core }), expect.anything()) }) it('Should deliver a "Rate" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { rate_value: 4, type: RateType.App, subject_id: 'app_id' } Navigation.logRateEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { block: ContentBlock.Core }), expect.anything()) }) it('Should deliver a "Rate" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { rate_value: 7, type: RateType.App, subject_id: 'app_id' } expect(() => Navigation.logRateEvent(event)).toThrowError() }) it('Should deliver a "Track" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { action: TrackActions.ViewItem, item_id: "111", } const sentEvent = { action: TrackActions.ViewItem, item_id: "111", type: TrackTypes.ReferenceGuide } Navigation.logTrackEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Track, props: sentEvent }), expect.anything()) }) it('Should failed when sending a "Track" event with missing fields', async () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { action: TrackActions.ViewItem, } await expect(Navigation.logTrackEvent(event)).rejects.toThrowError() }) it('Should complain when mandatory fields are missing in media catalog', async () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const catalogRepository = new CatalogRepository( `dummy-url`, mockSender ) Navigation.init(catalogRepository) const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { type: AudioVideoType.Video, time: 1000, id: 'id-media-event', action: MediaActionForVideo.Play, } await expect(Navigation.logMediaEvent(event, { resolution: '1080i' })).rejects.toThrowError() }) it('Should deliver a "Media" event with e-elearning type', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { contentBlock: ContentBlock.ELearning, type: ImageType.Image, id: 'id-media-event', action: MediaActionForImage.Play, } Navigation.logMediaEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { block: ContentBlock.ELearning }), expect.anything()) }) it('Should deliver a "Page" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { path: '/mypath', title: 'page-title' } Navigation.logPageEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Page, props: event }), expect.anything()) }) it('Should deliver a "Login" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const props: UserInfo = { action: IdentifyAction.Login, user_props: {} } Navigation.logIdentifyEvent(props) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Identify, props }), expect.anything()) }) it('Should deliver a "Delivery" event with the content block set to ECommerce - no call to setCurrentBlock', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { id: "1", action: DeliveryAction.Delivered, order_id: '11', } ECommerce.logDeliveryEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: ECommerceTypes.Delivery, block: ContentBlock.ECommerce }), expect.anything()) }) it('Should deliver a "Delivery" event with the contentBlock set to ECommerce - call to setCurrentBlock', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { id: "1", action: DeliveryAction.Delivered, order_id: '11', } Navigation.setCurrentBlock(ContentBlock.ELearning) ECommerce.logDeliveryEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: ECommerceTypes.Delivery, block: ContentBlock.ECommerce }), expect.anything()) }) it('Should deliver a "Page" event with a default contentBlock that have been overwritten', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.ELearning, DEFAULT_DEVICE_ID) const event = { path: '/mypath', title: 'page-title' } Navigation.logPageEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Page, block: ContentBlock.ELearning }), expect.anything()) }) it('Should deliver a "Page" event with a default contentBlock that have been overwritten', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.ELearning, DEFAULT_DEVICE_ID) const event = { path: '/mypath', title: 'page-title' } Navigation.logPageEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Page, block: ContentBlock.ELearning }), expect.anything()) }) it('Should deliver a "Page" event after setting explicitily the block name', async () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { path: '/mypath', title: 'page-title' } Navigation.setCurrentBlock(ContentBlock.ECommerce) await new Promise((r) => setTimeout(r, 20)); Navigation.logPageEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Page, block: ContentBlock.ECommerce }), expect.anything()) }) it('Should discard page events where duration is 0', async () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { path: '/mypath', title: 'page-title', duration: 0 } Navigation.logPageEvent(event) expect(senderSpy).toBeCalledTimes(0) }) it('Should not discard page events if duration is not present', async () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { path: '/mypath', title: 'page-title' } Navigation.logPageEvent(event) expect(senderSpy).toBeCalledTimes(1) }) it('Should deliver a "PushNotification" event', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { nudge_id: 111, type: NudgeResponseType.Push, response: { action: NudgeAction.Discard } } Navigation.logPushNotificationEvent(event) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.NudgeResponse, props: event }), expect.anything()) }) it('Should deliver a "Search" event with a specific content block', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const userEvent = { contentBlock: ContentBlock.ECommerce, page: 0, query: 'query-string', results_ids: [{id:'1', type: ItemType.Drug}, {id: '2', type: ItemType.Drug}], filter: { param: '11' } } const internalEvent = { page: 0, query: 'query-string', results_list: [{id:'1', type: ItemType.Drug}, {id: '2', type: ItemType.Drug}], filter: { param: '11' } } Navigation.logSearchEvent(userEvent, '11',true) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Search, props: expect.objectContaining(internalEvent) // we don't care the id in this assertion }), expect.anything()) // assert that the SDK has added the search ID expect((senderSpy.mock.calls[0][2] as any).props.id).toBeDefined() const eventDelivered = { block: ContentBlock.ECommerce } expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining(eventDelivered), expect.anything()) }) it('Should deliver a "Search" event for the default content block', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const event = { page: 0, query: 'query-string', results_ids: ['1', '2'], filter: { param: '11' } } const eventDelivered = { block: ContentBlock.Core } Navigation.logSearchEvent(event, '11', true) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining(eventDelivered), expect.anything()) // assert that the SDK has added the search ID expect((senderSpy.mock.calls[0][2] as any).props.id).toBeDefined() }) it('Should deliver a "Search" event adapting list of ID to list of TypedItems', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const userEvent = { contentBlock: ContentBlock.ECommerce, page: 0, query: 'query-string', results_ids: ['1', '2'], filter: { param: '11' } } const internalEvent = { page: 0, query: 'query-string', results_list: [{id:'1', type: ItemType.Drug}, {id: '2', type: ItemType.Drug}], filter: { param: '11' } } Navigation.logSearchEvent(userEvent, '11',true) expect(senderSpy).toBeCalledWith( expect.anything(), expect.anything(), expect.objectContaining( { type: NavigationTypes.Search, props: expect.objectContaining(internalEvent) // we don't care the id in this assertion }), expect.anything()) }) // it('Should throw an exception on "Search" - malformed list of result_ids, first string, rest objects', () => { // const DEFAULT_DEVICE_ID = 'web_sdk_device_id' // // const senderSpy = jest.spyOn(mockSender, 'add') // const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) // // const userEvent = { // contentBlock: ContentBlock.ECommerce, // page: 0, // query: 'query-string', // results_ids: ['1', {id: '2', type: ItemType.Drug}], // filter: { param: '11' } // } // // // expect(async () => Navigation.logSearchEvent(userEvent, '11',true)).rejects.toThrowError() // }) // // // it('Should throw an exception on "Search" - malformed list of result_ids, first object, rest strings', () => { // const DEFAULT_DEVICE_ID = 'web_sdk_device_id' // // const senderSpy = jest.spyOn(mockSender, 'add') // const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) // // const userEvent = { // contentBlock: ContentBlock.ECommerce, // page: 0, // query: 'query-string', // results_ids: [{id: '2', type: ItemType.Drug}, '1'], // filter: { param: '11' } // } // // expect(async () => Navigation.logSearchEvent(userEvent, '11',true)).rejects.toThrowError() // }) it('Should throw an exception on "Search" - repeated ids', () => { const DEFAULT_DEVICE_ID = 'web_sdk_device_id' const senderSpy = jest.spyOn(mockSender, 'add') const bsCore = BsCore.createInstance(mockSender as any, MockImpressionsDetector, false, ContentBlock.Core, DEFAULT_DEVICE_ID) const userEvent = { contentBlock: ContentBlock.ECommerce, page: 0, query: 'query-string', results_ids: ['1', '1'], filter: { param: '11' } } expect(async () => Navigation.logSearchEvent(userEvent, '11',true)).rejects.toThrowError() }) }) })