UNPKG

salsify-experiences-sdk

Version:

SDK to be used by commerce websites to implement product experiences.

182 lines (144 loc) 5.54 kB
/** * @jest-environment jsdom */ import { createLogger } from '../utils/logger' import SdkApi, { Context } from '../api' import * as EnhancedContentApi from '../enhancedContent' import { getCookie, setCookie } from '../utils/cookies' import { makeResponse } from '../__tests__/helpers' import request from '../utils/request' jest.mock('../utils/request') const headMock = request.head as jest.Mock const getMock = request.get as jest.Mock const exampleContent = '<div>enhanced-content</div>' const emptyContent = '' const logMock = jest.fn() jest.mock('../utils/logger') let context: Context | undefined ;(createLogger as jest.Mock).mockImplementation(function (ctx: Context) { context = ctx return { log: logMock } }) interface Cookies { [key: string]: string | undefined } let cookies: Cookies = {} jest.mock('../utils/cookies', () => { return { setCookie: jest.fn((key: string, val: string) => (cookies[key] = val)), getCookie: jest.fn((key: string) => cookies[key]), deleteCookie: jest.fn((key: string) => delete cookies[key]), } }) const defaultOptions = { clientId: 'client-id', } const uuidRegex = /^[0-9a-f]{8}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{12}$/ describe('SdkApi', () => { let sdk: SdkApi beforeEach(() => { sdk = new SdkApi('npm') cookies = {} headMock.mockImplementation(() => makeResponse(exampleContent)) getMock.mockImplementation(() => makeResponse(emptyContent)) context = undefined }) afterEach(() => { logMock.mockReset() headMock.mockClear() getMock.mockClear() }) test('constructed uninitialized', () => { expect(sdk.initialized).toBe(false) const accessEc = (): EnhancedContentApi.default => sdk.enhancedContent expect(accessEc).toThrow('Salsify Experiences SDK has not been initialized.') }) test('can only be initialized once', () => { sdk.init(defaultOptions) const reinit = (): void => sdk.init(defaultOptions) expect(reinit).toThrow('Salsify Experiences SDK has already been initialized.') }) test('allows API access once initialized', () => { sdk.init(defaultOptions) expect(sdk.enhancedContent).toBeTruthy() }) test('allow events API access once initialized', () => { sdk.init(defaultOptions) expect(sdk.events).toBeTruthy() }) test('cookie is not set when tracking is false', () => { sdk.init({ ...defaultOptions, ...{ tracking: false } }) expect(getCookie('salsify_session_id')).toBeUndefined() }) test('cookie is set by default', () => { sdk.init(defaultOptions) expect(getCookie('salsify_session_id')).toBeDefined() }) test('cookie is set when tracking is true', () => { sdk.init({ ...defaultOptions, ...{ tracking: true } }) expect(getCookie('salsify_session_id')).toBeDefined() }) test('cookie is remove if already set when tracking is set to false', () => { setCookie('salsify_session_id', 'abc') sdk.init({ ...defaultOptions, ...{ tracking: false } }) expect(getCookie('salsify_session_id')).toBeUndefined() }) test('iframe context listener is attached', () => { window.addEventListener = jest.fn() sdk.init({ ...defaultOptions, ...{ tracking: false } }) expect(window.addEventListener).toHaveBeenCalledTimes(2) }) test('iframe context listener called with tracking: false', () => { const attachIframeContextListenerSpy = jest.spyOn(EnhancedContentApi, 'attachIframeContextListener') sdk.init({ ...defaultOptions, ...{ tracking: false } }) expect(attachIframeContextListenerSpy).toHaveBeenCalledWith( expect.objectContaining({ tracking: false, sessionId: 'NOT_TRACKED', pageSessionId: expect.stringMatching(uuidRegex), }) ) }) test('iframe context listener called with tracking: true', () => { const attachIframeContextListenerSpy = jest.spyOn(EnhancedContentApi, 'attachIframeContextListener') sdk.init({ ...defaultOptions, ...{ tracking: true } }) expect(attachIframeContextListenerSpy).toHaveBeenCalledWith( expect.objectContaining({ tracking: true, sessionId: expect.stringMatching(uuidRegex), pageSessionId: expect.stringMatching(uuidRegex), }) ) }) test('it sends and restarts time-on-page on navigation event', async () => { sdk.init({ ...defaultOptions, ...{ tracking: true } }) await sdk.enhancedContent.renderIframe(document.createElement('div'), 'foo', 'bar') sdk.events.navigation({ productIdType: 'foo', productId: 'bar' }) expect(logMock.mock.calls.filter(([event]) => event === 'time_on_page')).toEqual([ ['time_on_page', expect.objectContaining({ timeOnPage: expect.any(Number) })], ]) }) describe('crypto.randomUUID not available (e.g. insecure context)', () => { const { randomUUID } = crypto beforeEach(() => { // @ts-ignore crypto.randomUUID = undefined }) afterEach(() => { crypto.randomUUID = randomUUID }) test('sessionId is undefined', () => { sdk.init(defaultOptions) expect(context).toMatchObject({ sessionId: undefined }) }) test('pageSessionId is undefined', () => { sdk.init(defaultOptions) expect(context).toMatchObject({ pageSessionId: undefined }) }) test('pageSessionId is still undefined after reset', () => { sdk.init(defaultOptions) sdk.events.navigation({ productIdType: 'foo', productId: 'bar' }) expect(context).toMatchObject({ pageSessionId: undefined }) }) }) })