import { describe, it, expect } from 'vitest'; import { createEnvironmentSpecificLoggedDialog, type WindowDialogCreationFunction, type BrowserDialogCreationFunction, type DialogLoggingDecorator, } from '@/presentation/components/Shared/Hooks/Dialog/ClientDialogFactory'; import type { RuntimeEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironment'; import { RuntimeEnvironmentStub } from '@tests/unit/shared/Stubs/RuntimeEnvironmentStub'; import { DialogStub } from '@tests/unit/shared/Stubs/DialogStub'; import { collectExceptionMessage } from '@tests/unit/shared/ExceptionCollector'; import type { Dialog } from '@/presentation/common/Dialog'; describe('ClientDialogFactory', () => { describe('createEnvironmentSpecificLoggedDialog', () => { describe('dialog selection based on environment', () => { describe('when in non-desktop environment', () => { it('provides a browser dialog', () => { // arrange const expectedDialog = new DialogStub(); const context = new DialogCreationTestSetup() .withEnvironment(new RuntimeEnvironmentStub().withIsRunningAsDesktopApplication(false)) .withBrowserDialogFactory(() => expectedDialog); // act const actualDialog = context.createDialogForTest(); // assert expect(expectedDialog).to.equal(actualDialog); }); }); describe('when in desktop environment', () => { it('provides a window-injected dialog', () => { // arrange const expectedDialog = new DialogStub(); const context = new DialogCreationTestSetup() .withEnvironment(new RuntimeEnvironmentStub().withIsRunningAsDesktopApplication(true)) .withWindowInjectedDialogFactory(() => expectedDialog); // act const actualDialog = context.createDialogForTest(); // assert expect(expectedDialog).to.equal(actualDialog); }); it('throws error if window-injected dialog is not available', () => { // arrange const expectedError = 'Failed to retrieve Dialog API from window object in desktop environment.'; const context = new DialogCreationTestSetup() .withEnvironment(new RuntimeEnvironmentStub().withIsRunningAsDesktopApplication(true)) .withWindowInjectedDialogFactory(() => undefined); // act const act = () => context.createDialogForTest(); // assert const actualError = collectExceptionMessage(act); expect(actualError).to.include(expectedError); }); }); }); describe('dialog decoration with logging', () => { it('returns a dialog decorated with logging', () => { // arrange const expectedLoggingDialogStub = new DialogStub(); const decoratorStub: DialogLoggingDecorator = () => expectedLoggingDialogStub; const context = new DialogCreationTestSetup() .withDialogLoggingDecorator(decoratorStub); // act const actualDialog = context.createDialogForTest(); // assert expect(expectedLoggingDialogStub).to.equal(actualDialog); }); it('applies logging decorator to the provided dialog', () => { // arrange const expectedDialog = new DialogStub(); let actualDecoratedDialog: Dialog | undefined; const decoratorStub: DialogLoggingDecorator = (dialog) => { actualDecoratedDialog = dialog; return new DialogStub(); }; const context = new DialogCreationTestSetup() .withEnvironment(new RuntimeEnvironmentStub().withIsRunningAsDesktopApplication(false)) .withBrowserDialogFactory(() => expectedDialog) .withDialogLoggingDecorator(decoratorStub); // act context.createDialogForTest(); // assert expect(expectedDialog).to.equal(actualDecoratedDialog); }); }); }); }); class DialogCreationTestSetup { private environment: RuntimeEnvironment = new RuntimeEnvironmentStub(); private browserDialogFactory: BrowserDialogCreationFunction = () => new DialogStub(); private windowInjectedDialogFactory: WindowDialogCreationFunction = () => new DialogStub(); private dialogLoggingDecorator: DialogLoggingDecorator = (dialog) => dialog; public withEnvironment(environment: RuntimeEnvironment): this { this.environment = environment; return this; } public withBrowserDialogFactory(browserDialogFactory: BrowserDialogCreationFunction): this { this.browserDialogFactory = browserDialogFactory; return this; } public withWindowInjectedDialogFactory( windowInjectedDialogFactory: WindowDialogCreationFunction, ): this { this.windowInjectedDialogFactory = windowInjectedDialogFactory; return this; } public withDialogLoggingDecorator( dialogLoggingDecorator: DialogLoggingDecorator, ): this { this.dialogLoggingDecorator = dialogLoggingDecorator; return this; } public createDialogForTest() { return createEnvironmentSpecificLoggedDialog( this.environment, this.dialogLoggingDecorator, this.windowInjectedDialogFactory, this.browserDialogFactory, ); } }