From d69fb604a83f2d9621cd704533dcb2bd039c7422 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 14 Dec 2023 20:13:54 +0000 Subject: [PATCH] feat: remove given from another test file (#940) * some progress * more prgoress * and more * and even even more * feat: remove given from another test file --- src/__tests__/sessionid.js | 288 ----------------------------------- src/__tests__/sessionid.ts | 297 +++++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+), 288 deletions(-) delete mode 100644 src/__tests__/sessionid.js create mode 100644 src/__tests__/sessionid.ts diff --git a/src/__tests__/sessionid.js b/src/__tests__/sessionid.js deleted file mode 100644 index 54bcd0496..000000000 --- a/src/__tests__/sessionid.js +++ /dev/null @@ -1,288 +0,0 @@ -import { SessionIdManager } from '../sessionid' -import { SESSION_ID } from '../constants' -import { sessionStore } from '../storage' -import { uuidv7 } from '../uuidv7' - -jest.mock('../uuidv7') -jest.mock('../storage') - -describe('Session ID manager', () => { - given('subject', () => given.sessionIdManager.checkAndGetSessionAndWindowId(given.readOnly, given.timestamp)) - given('sessionIdManager', () => new SessionIdManager(given.config, given.persistence)) - - given('persistence', () => ({ - props: { [SESSION_ID]: given.storedSessionIdData }, - register: jest.fn(), - disabled: given.disablePersistence, - })) - given('disablePersistence', () => false) - - given('config', () => ({ - persistence_name: 'persistance-name', - })) - - given('timestamp', () => 1603107479471) - - given('now', () => given.timestamp + 1000) - - beforeEach(() => { - sessionStore.is_supported.mockReturnValue(true) - const mockDate = new Date(given.now) - jest.spyOn(global, 'Date').mockImplementation(() => mockDate) - uuidv7.mockReturnValue('newUUID') - }) - - describe('new session id manager', () => { - it('generates an initial session id and window id, and saves them', () => { - expect(given.subject).toMatchObject({ - windowId: 'newUUID', - sessionId: 'newUUID', - sessionStartTimestamp: given.timestamp, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'newUUID', given.timestamp], - }) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') - }) - - it('generates an initial session id and window id, and saves them even if readOnly is true', () => { - given('readOnly', () => true) - expect(given.subject).toMatchObject({ - windowId: 'newUUID', - sessionId: 'newUUID', - sessionStartTimestamp: given.timestamp, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'newUUID', given.timestamp], - }) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') - }) - }) - - describe('stored session data', () => { - given('timestampOfSessionStart', () => given.now - 3600) - - given('storedSessionIdData', () => [given.now, 'oldSessionID', given.timestampOfSessionStart]) - beforeEach(() => { - sessionStore.parse.mockReturnValue('oldWindowID') - }) - - it('reuses old ids and updates the session timestamp if not much time has passed', () => { - expect(given.subject).toEqual({ - windowId: 'oldWindowID', - sessionId: 'oldSessionID', - sessionStartTimestamp: given.timestampOfSessionStart, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'oldSessionID', given.timestampOfSessionStart], - }) - }) - - it('reuses old ids and does not update the session timestamp if > 30m pass and readOnly is true', () => { - let thirtyMinutesAndOneSecond = 60 * 60 * 30 + 1 - const oldTimestamp = given.now - thirtyMinutesAndOneSecond - const sessionStart = oldTimestamp - 1000 - - given('storedSessionIdData', () => [oldTimestamp, 'oldSessionID', sessionStart]) - given('readOnly', () => true) - - expect(given.subject).toEqual({ - windowId: 'oldWindowID', - sessionId: 'oldSessionID', - sessionStartTimestamp: sessionStart, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [oldTimestamp, 'oldSessionID', sessionStart], - }) - }) - - it('generates only a new window id, and saves it when there is no previous window id set', () => { - sessionStore.parse.mockReturnValue(null) - expect(given.subject).toEqual({ - windowId: 'newUUID', - sessionId: 'oldSessionID', - sessionStartTimestamp: given.timestampOfSessionStart, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'oldSessionID', given.timestampOfSessionStart], - }) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') - }) - - it('generates a new session id and window id, and saves it when >30m since last event', () => { - const oldTimestamp = 1602107460000 - given('storedSessionIdData', () => [oldTimestamp, 'oldSessionID', given.timestampOfSessionStart]) - - expect(given.subject).toEqual({ - windowId: 'newUUID', - sessionId: 'newUUID', - sessionStartTimestamp: given.timestamp, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'newUUID', given.timestamp], - }) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') - }) - - it('generates a new session id and window id, and saves it when >24 hours since start timestamp', () => { - const oldTimestamp = 1602107460000 - const twentyFourHours = 3600 * 24 - given('storedSessionIdData', () => [oldTimestamp, 'oldSessionID', given.timestampOfSessionStart]) - given('timestamp', () => given.timestampOfSessionStart + twentyFourHours) - - expect(given.subject).toEqual({ - windowId: 'newUUID', - sessionId: 'newUUID', - sessionStartTimestamp: given.timestamp, - }) - - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'newUUID', given.timestamp], - }) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') - }) - - it('generates a new session id and window id, and saves it when >24 hours since start timestamp even when readonly is true', () => { - const oldTimestamp = 1602107460000 - const twentyFourHoursAndOneSecond = (3600 * 24 + 1) * 1000 - given('storedSessionIdData', () => [oldTimestamp, 'oldSessionID', given.timestampOfSessionStart]) - given('timestamp', () => given.timestampOfSessionStart + twentyFourHoursAndOneSecond) - given('readOnly', () => true) - - expect(given.subject).toEqual({ - windowId: 'newUUID', - sessionId: 'newUUID', - sessionStartTimestamp: given.timestamp, - }) - - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'newUUID', given.timestamp], - }) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') - }) - - it('uses the current time if no timestamp is provided', () => { - const now = new Date().getTime() - const oldTimestamp = 1601107460000 - given('storedSessionIdData', () => [oldTimestamp, 'oldSessionID', given.timestampOfSessionStart]) - given('timestamp', () => undefined) - expect(given.subject).toEqual({ - windowId: 'newUUID', - sessionId: 'newUUID', - sessionStartTimestamp: now, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.now, 'newUUID', given.now], - }) - }) - - it('populates the session start timestamp for a browser with no start time stored', () => { - given('storedSessionIdData', () => [given.timestamp, 'oldSessionID']) - expect(given.subject).toEqual({ - windowId: 'oldWindowID', - sessionId: 'oldSessionID', - sessionStartTimestamp: given.timestamp, - }) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [given.timestamp, 'oldSessionID', given.timestamp], - }) - }) - }) - - describe('window id storage', () => { - it('stores and retrieves a window_id', () => { - given.sessionIdManager._setWindowId('newWindowId') - expect(given.sessionIdManager._getWindowId()).toEqual('newWindowId') - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newWindowId') - }) - it('stores and retrieves a window_id if persistance is disabled and storage is not used', () => { - given('disablePersistence', () => true) - given.sessionIdManager._setWindowId('newWindowId') - expect(given.sessionIdManager._getWindowId()).toEqual('newWindowId') - expect(sessionStore.set).not.toHaveBeenCalled() - }) - it('stores and retrieves a window_id if sessionStorage is not supported', () => { - sessionStore.is_supported.mockReturnValue(false) - given.sessionIdManager._setWindowId('newWindowId') - expect(given.sessionIdManager._getWindowId()).toEqual('newWindowId') - expect(sessionStore.set).not.toHaveBeenCalled() - }) - }) - - describe('session id storage', () => { - it('stores and retrieves a session id and timestamp', () => { - given.sessionIdManager._setSessionId('newSessionId', 1603107460000, 1603107460000) - expect(given.persistence.register).toHaveBeenCalledWith({ - [SESSION_ID]: [1603107460000, 'newSessionId', 1603107460000], - }) - expect(given.sessionIdManager._getSessionId()).toEqual([1603107460000, 'newSessionId', 1603107460000]) - }) - }) - - describe('reset session id', () => { - it('clears the existing session id', () => { - given.sessionIdManager.resetSessionId() - expect(given.persistence.register).toHaveBeenCalledWith({ [SESSION_ID]: [null, null, null] }) - }) - it('a new session id is generated when called', () => { - given('storedSessionIdData', () => [null, null, null]) - expect(given.sessionIdManager._getSessionId()).toEqual([null, null, null]) - expect(given.subject).toMatchObject({ - windowId: 'newUUID', - sessionId: 'newUUID', - }) - }) - }) - - describe('primary_window_exists_storage_key', () => { - it('if primary_window_exists key does not exist, do not cycle window id', () => { - // setup - sessionStore.parse.mockImplementation((storeKey) => - storeKey === 'ph_persistance-name_primary_window_exists' ? undefined : 'oldWindowId' - ) - // expect - expect(given.sessionIdManager._windowId).toEqual('oldWindowId') - expect(sessionStore.remove).toHaveBeenCalledTimes(0) - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_primary_window_exists', true) - }) - it('if primary_window_exists key exists, cycle window id', () => { - // setup - sessionStore.parse.mockImplementation((storeKey) => - storeKey === 'ph_persistance-name__primary_window_exists' ? true : 'oldWindowId' - ) - // expect - expect(given.sessionIdManager._windowId).toEqual(undefined) - expect(sessionStore.remove).toHaveBeenCalledWith('ph_persistance-name_window_id') - expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_primary_window_exists', true) - }) - }) - - describe('custom session_idle_timeout_seconds', () => { - const mockSessionManager = (timeout) => - new SessionIdManager( - { - session_idle_timeout_seconds: timeout, - }, - given.persistence, - given.uuidFn - ) - - beforeEach(() => { - console.warn = jest.fn() - }) - - it('uses the custom session_idle_timeout_seconds if within bounds', () => { - window.POSTHOG_DEBUG = true - expect(mockSessionManager(61)._sessionTimeoutMs).toEqual(61 * 1000) - expect(console.warn).toBeCalledTimes(0) - expect(mockSessionManager(59)._sessionTimeoutMs).toEqual(60 * 1000) - expect(console.warn).toBeCalledTimes(1) - expect(mockSessionManager(30 * 60 - 1)._sessionTimeoutMs).toEqual((30 * 60 - 1) * 1000) - expect(console.warn).toBeCalledTimes(1) - expect(mockSessionManager(30 * 60 + 1)._sessionTimeoutMs).toEqual(30 * 60 * 1000) - expect(console.warn).toBeCalledTimes(2) - expect(mockSessionManager('foobar')._sessionTimeoutMs).toEqual(30 * 60 * 1000) - expect(console.warn).toBeCalledTimes(3) - }) - }) -}) diff --git a/src/__tests__/sessionid.ts b/src/__tests__/sessionid.ts new file mode 100644 index 000000000..077679494 --- /dev/null +++ b/src/__tests__/sessionid.ts @@ -0,0 +1,297 @@ +import { SessionIdManager } from '../sessionid' +import { SESSION_ID } from '../constants' +import { sessionStore } from '../storage' +import { uuidv7 } from '../uuidv7' +import { PostHogConfig, Properties } from '../types' +import { PostHogPersistence } from '../posthog-persistence' +import { assignableWindow } from '../utils/globals' + +jest.mock('../uuidv7') +jest.mock('../storage') + +describe('Session ID manager', () => { + let timestamp: number | undefined + let now: number + let timestampOfSessionStart: number + const config: Partial = { + persistence_name: 'persistance-name', + } + + let persistence: { props: Properties } & Partial + + const subject = (sessionIdManager: SessionIdManager, isReadOnly?: boolean) => + sessionIdManager.checkAndGetSessionAndWindowId(isReadOnly, timestamp) + const sessionIdMgr = (phPersistence: Partial) => + new SessionIdManager(config, phPersistence as PostHogPersistence) + + const originalDate = Date + + beforeEach(() => { + timestamp = 1603107479471 + now = timestamp + 1000 + + persistence = { + props: { [SESSION_ID]: undefined }, + register: jest.fn(), + disabled: false, + } + ;(sessionStore.is_supported as jest.Mock).mockReturnValue(true) + jest.spyOn(global, 'Date').mockImplementation(() => new originalDate(now)) + ;(uuidv7 as jest.Mock).mockReturnValue('newUUID') + }) + + describe('new session id manager', () => { + it('generates an initial session id and window id, and saves them', () => { + expect(subject(sessionIdMgr(persistence))).toMatchObject({ + windowId: 'newUUID', + sessionId: 'newUUID', + sessionStartTimestamp: timestamp, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'newUUID', timestamp], + }) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') + }) + + it('generates an initial session id and window id, and saves them even if readOnly is true', () => { + expect(subject(sessionIdMgr(persistence), true)).toMatchObject({ + windowId: 'newUUID', + sessionId: 'newUUID', + sessionStartTimestamp: timestamp, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'newUUID', timestamp], + }) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') + }) + }) + + describe('stored session data', () => { + beforeEach(() => { + ;(sessionStore.parse as jest.Mock).mockReturnValue('oldWindowID') + timestampOfSessionStart = now - 3600 + persistence.props[SESSION_ID] = [now, 'oldSessionID', timestampOfSessionStart] + }) + + it('reuses old ids and updates the session timestamp if not much time has passed', () => { + expect(subject(sessionIdMgr(persistence))).toEqual({ + windowId: 'oldWindowID', + sessionId: 'oldSessionID', + sessionStartTimestamp: timestampOfSessionStart, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'oldSessionID', timestampOfSessionStart], + }) + }) + + it('reuses old ids and does not update the session timestamp if > 30m pass and readOnly is true', () => { + const thirtyMinutesAndOneSecond = 60 * 60 * 30 + 1 + const oldTimestamp = now - thirtyMinutesAndOneSecond + const sessionStart = oldTimestamp - 1000 + + persistence.props[SESSION_ID] = [oldTimestamp, 'oldSessionID', sessionStart] + + expect(subject(sessionIdMgr(persistence), true)).toEqual({ + windowId: 'oldWindowID', + sessionId: 'oldSessionID', + sessionStartTimestamp: sessionStart, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [oldTimestamp, 'oldSessionID', sessionStart], + }) + }) + + it('generates only a new window id, and saves it when there is no previous window id set', () => { + ;(sessionStore.parse as jest.Mock).mockReturnValue(null) + expect(subject(sessionIdMgr(persistence))).toEqual({ + windowId: 'newUUID', + sessionId: 'oldSessionID', + sessionStartTimestamp: timestampOfSessionStart, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'oldSessionID', timestampOfSessionStart], + }) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') + }) + + it('generates a new session id and window id, and saves it when >30m since last event', () => { + const oldTimestamp = 1602107460000 + persistence.props[SESSION_ID] = [oldTimestamp, 'oldSessionID', timestampOfSessionStart] + + expect(subject(sessionIdMgr(persistence))).toEqual({ + windowId: 'newUUID', + sessionId: 'newUUID', + sessionStartTimestamp: timestamp, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'newUUID', timestamp], + }) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') + }) + + it('generates a new session id and window id, and saves it when >24 hours since start timestamp', () => { + const oldTimestamp = 1602107460000 + const twentyFourHours = 3600 * 24 + persistence.props[SESSION_ID] = [oldTimestamp, 'oldSessionID', timestampOfSessionStart] + timestamp = timestampOfSessionStart + twentyFourHours + + expect(subject(sessionIdMgr(persistence))).toEqual({ + windowId: 'newUUID', + sessionId: 'newUUID', + sessionStartTimestamp: timestamp, + }) + + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'newUUID', timestamp], + }) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') + }) + + it('generates a new session id and window id, and saves it when >24 hours since start timestamp even when readonly is true', () => { + const oldTimestamp = 1602107460000 + const twentyFourHoursAndOneSecond = (3600 * 24 + 1) * 1000 + persistence.props[SESSION_ID] = [oldTimestamp, 'oldSessionID', timestampOfSessionStart] + timestamp = timestampOfSessionStart + twentyFourHoursAndOneSecond + now = timestamp + 1000 + + expect(subject(sessionIdMgr(persistence), true)).toEqual({ + windowId: 'newUUID', + sessionId: 'newUUID', + sessionStartTimestamp: timestamp, + }) + + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'newUUID', timestamp], + }) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newUUID') + }) + + it('uses the current time if no timestamp is provided', () => { + const now = new Date().getTime() + const oldTimestamp = 1601107460000 + persistence.props[SESSION_ID] = [oldTimestamp, 'oldSessionID', timestampOfSessionStart] + timestamp = undefined + expect(subject(sessionIdMgr(persistence))).toEqual({ + windowId: 'newUUID', + sessionId: 'newUUID', + sessionStartTimestamp: now, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [now, 'newUUID', now], + }) + }) + + it('populates the session start timestamp for a browser with no start time stored', () => { + persistence.props[SESSION_ID] = [timestamp, 'oldSessionID'] + expect(subject(sessionIdMgr(persistence))).toEqual({ + windowId: 'oldWindowID', + sessionId: 'oldSessionID', + sessionStartTimestamp: timestamp, + }) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [timestamp, 'oldSessionID', timestamp], + }) + }) + }) + + describe('window id storage', () => { + it('stores and retrieves a window_id', () => { + const sessionIdManager = sessionIdMgr(persistence) + sessionIdManager['_setWindowId']('newWindowId') + expect(sessionIdManager['_getWindowId']()).toEqual('newWindowId') + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_window_id', 'newWindowId') + }) + it('stores and retrieves a window_id if persistance is disabled and storage is not used', () => { + persistence.disabled = true + const sessionIdManager = sessionIdMgr(persistence) + sessionIdManager['_setWindowId']('newWindowId') + expect(sessionIdManager['_getWindowId']()).toEqual('newWindowId') + expect(sessionStore.set).not.toHaveBeenCalled() + }) + it('stores and retrieves a window_id if sessionStorage is not supported', () => { + ;(sessionStore.is_supported as jest.Mock).mockReturnValue(false) + const sessionIdManager = sessionIdMgr(persistence) + sessionIdManager['_setWindowId']('newWindowId') + expect(sessionIdManager['_getWindowId']()).toEqual('newWindowId') + expect(sessionStore.set).not.toHaveBeenCalled() + }) + }) + + describe('session id storage', () => { + it('stores and retrieves a session id and timestamp', () => { + const sessionIdManager = sessionIdMgr(persistence) + sessionIdManager['_setSessionId']('newSessionId', 1603107460000, 1603107460000) + expect(persistence.register).toHaveBeenCalledWith({ + [SESSION_ID]: [1603107460000, 'newSessionId', 1603107460000], + }) + expect(sessionIdManager['_getSessionId']()).toEqual([1603107460000, 'newSessionId', 1603107460000]) + }) + }) + + describe('reset session id', () => { + it('clears the existing session id', () => { + sessionIdMgr(persistence).resetSessionId() + expect(persistence.register).toHaveBeenCalledWith({ [SESSION_ID]: [null, null, null] }) + }) + it('a new session id is generated when called', () => { + persistence.props[SESSION_ID] = [null, null, null] + expect(sessionIdMgr(persistence)['_getSessionId']()).toEqual([null, null, null]) + expect(subject(sessionIdMgr(persistence))).toMatchObject({ + windowId: 'newUUID', + sessionId: 'newUUID', + }) + }) + }) + + describe('primary_window_exists_storage_key', () => { + it('if primary_window_exists key does not exist, do not cycle window id', () => { + // setup + ;(sessionStore.parse as jest.Mock).mockImplementation((storeKey: string) => + storeKey === 'ph_persistance-name_primary_window_exists' ? undefined : 'oldWindowId' + ) + // expect + expect(sessionIdMgr(persistence)['_windowId']).toEqual('oldWindowId') + expect(sessionStore.remove).toHaveBeenCalledTimes(0) + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_primary_window_exists', true) + }) + it('if primary_window_exists key exists, cycle window id', () => { + // setup + ;(sessionStore.parse as jest.Mock).mockImplementation((storeKey: string) => + storeKey === 'ph_persistance-name__primary_window_exists' ? true : 'oldWindowId' + ) + // expect + expect(sessionIdMgr(persistence)['_windowId']).toEqual(undefined) + expect(sessionStore.remove).toHaveBeenCalledWith('ph_persistance-name_window_id') + expect(sessionStore.set).toHaveBeenCalledWith('ph_persistance-name_primary_window_exists', true) + }) + }) + + describe('custom session_idle_timeout_seconds', () => { + const mockSessionManager = (timeout: number | undefined) => + new SessionIdManager( + { + session_idle_timeout_seconds: timeout, + }, + persistence as PostHogPersistence + ) + + beforeEach(() => { + console.warn = jest.fn() + }) + + it('uses the custom session_idle_timeout_seconds if within bounds', () => { + assignableWindow.POSTHOG_DEBUG = true + expect(mockSessionManager(61)['_sessionTimeoutMs']).toEqual(61 * 1000) + expect(console.warn).toBeCalledTimes(0) + expect(mockSessionManager(59)['_sessionTimeoutMs']).toEqual(60 * 1000) + expect(console.warn).toBeCalledTimes(1) + expect(mockSessionManager(30 * 60 - 1)['_sessionTimeoutMs']).toEqual((30 * 60 - 1) * 1000) + expect(console.warn).toBeCalledTimes(1) + expect(mockSessionManager(30 * 60 + 1)['_sessionTimeoutMs']).toEqual(30 * 60 * 1000) + expect(console.warn).toBeCalledTimes(2) + // @ts-expect-error - test invalid input + expect(mockSessionManager('foobar')['_sessionTimeoutMs']).toEqual(30 * 60 * 1000) + expect(console.warn).toBeCalledTimes(3) + }) + }) +})