import { datadogRum } from '@datadog/browser-rum'; import { DATADOG_RUM_FOR_DEV } from '../constants'; import { installDevConsole } from '../dev-console'; import { clearOverride, enableOverride } from '../override'; jest.mock('@datadog/browser-rum'); jest.mock('../override'); describe('[datadog-rum] runtime-override/dev-console', () => { const originalLocation = window.location; const reload = jest.fn(); const handle = () => (globalThis as { datadogRumForDev?: { start: () => void; stop: () => void } }) .datadogRumForDev!; const storageCalls = () => jest.mocked(globalThis.addEventListener).mock.calls.filter(([type]) => type === 'storage'); let infoSpy: jest.SpyInstance; beforeAll(() => { delete (window as { location?: Location }).location; (window as unknown as { location: { reload: jest.Mock } }).location = { reload }; }); afterAll(() => { (window as unknown as { location: Location }).location = originalLocation; }); afterEach(() => { jest.restoreAllMocks(); }); beforeEach(() => { jest.clearAllMocks(); delete (globalThis as { datadogRumForDev?: unknown }).datadogRumForDev; infoSpy = jest.spyOn(console, 'info').mockImplementation(() => {}); jest.spyOn(globalThis, 'addEventListener').mockImplementation(() => {}); installDevConsole(); }); test('installs the global handle', () => { expect(handle()).toEqual({ start: expect.any(Function), stop: expect.any(Function) }); }); test('registers a single storage listener', () => { expect(storageCalls()).toHaveLength(1); }); describe('when installed again', () => { let previous: ReturnType; beforeEach(() => { previous = handle(); installDevConsole(); }); test('keeps the same handle', () => { expect(handle()).toBe(previous); }); test('does not add another storage listener', () => { expect(storageCalls()).toHaveLength(1); }); }); describe('the storage listener', () => { let event: { key: string }; const subject = () => (storageCalls()[0][1] as EventListener)(event as unknown as Event); describe('when the override key changes', () => { beforeEach(() => (event = { key: DATADOG_RUM_FOR_DEV })); test('reloads sibling tabs', () => { subject(); expect(reload).toHaveBeenCalled(); }); }); describe('when an unrelated key changes', () => { beforeEach(() => (event = { key: 'other' })); test('does not reload', () => { subject(); expect(reload).not.toHaveBeenCalled(); }); }); }); describe('start', () => { const subject = () => handle().start(); test('enables the override', () => { subject(); expect(enableOverride).toHaveBeenCalled(); }); test('reloads the page', () => { subject(); expect(reload).toHaveBeenCalled(); }); test('logs to the console', () => { subject(); expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('start()')); }); }); describe('stop', () => { const subject = () => handle().stop(); test('ends the current Datadog session', () => { subject(); expect(datadogRum.stopSession).toHaveBeenCalled(); }); test('clears the override', () => { subject(); expect(clearOverride).toHaveBeenCalled(); }); test('reloads the page', () => { subject(); expect(reload).toHaveBeenCalled(); }); test('logs to the console', () => { subject(); expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('stop()')); }); describe('when ending the session fails', () => { beforeEach(() => jest.mocked(datadogRum.stopSession).mockImplementation(() => { throw new Error('not initialized'); }) ); test('does not throw', () => { expect(subject).not.toThrow(); }); test('still clears the override', () => { subject(); expect(clearOverride).toHaveBeenCalled(); }); }); }); });