Files
privacy.sexy/tests/unit/presentation/components/Shared/Hooks/Log/ClientLoggerFactory.spec.ts
undergroundwires 4212c7b9e0 Improve context for errors thrown by compiler
This commit introduces a custom error object to provide additional
context for errors throwing during parsing and compiling operations,
improving troubleshooting.

By integrating error context handling, the error messages become more
informative and user-friendly, providing sequence of trace with context
to aid in troubleshooting.

Changes include:

- Introduce custom error object that extends errors with contextual
  information. This replaces previous usages of `AggregateError` which
  is not displayed well by browsers when logged.
- Improve parsing functions to encapsulate error context with more
  details.
- Increase unit test coverage and refactor the related code to be more
  testable.
2024-05-25 13:55:30 +02:00

160 lines
5.4 KiB
TypeScript

// eslint-disable-next-line max-classes-per-file
import { describe, it } from 'vitest';
import type { RuntimeEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironment';
import type { Logger } from '@/application/Common/Log/Logger';
import { RuntimeEnvironmentStub } from '@tests/unit/shared/Stubs/RuntimeEnvironmentStub';
import { itIsSingletonFactory } from '@tests/unit/shared/TestCases/SingletonFactoryTests';
import { LoggerStub } from '@tests/unit/shared/Stubs/LoggerStub';
import { ClientLoggerFactory, type LoggerCreationFunction, type WindowAccessor } from '@/presentation/components/Shared/Hooks/Log/ClientLoggerFactory';
describe('ClientLoggerFactory', () => {
describe('Current', () => {
describe('singleton behavior', () => {
itIsSingletonFactory({
getter: () => ClientLoggerFactory.Current,
expectedType: ClientLoggerFactory,
});
});
});
describe('logger instantiation based on environment', () => {
const testCases: Array<{
readonly description: string,
readonly build: (
builder: ClientLoggerFactoryBuilder,
expectedLogger: Logger,
) => ClientLoggerFactory,
}> = [
{
description: 'production desktop environment',
build: (b, expectedLogger) => b
.withWindowInjectedLoggerFactory(() => expectedLogger)
.withEnvironment(new RuntimeEnvironmentStub()
.withIsRunningAsDesktopApplication(true)
.withIsNonProduction(false))
.withWindowAccessor(() => createWindowWithLogger())
.build(),
},
{
description: 'non-production desktop environment',
build: (b, expectedLogger) => b
.withWindowInjectedLoggerFactory(() => expectedLogger)
.withEnvironment(new RuntimeEnvironmentStub()
.withIsRunningAsDesktopApplication(true)
.withIsNonProduction(true))
.withWindowAccessor(() => createWindowWithLogger())
.build(),
},
{
description: 'non-production web environment',
build: (b, expectedLogger) => b
.withConsoleLoggerFactory(() => expectedLogger)
.withEnvironment(new RuntimeEnvironmentStub()
.withIsRunningAsDesktopApplication(false)
.withIsNonProduction(true))
.withWindowAccessor(() => createWindowWithLogger())
.build(),
},
{
description: 'production web environment',
build: (b, expectedLogger) => b
.withNoopLoggerFactory(() => expectedLogger)
.withEnvironment(new RuntimeEnvironmentStub()
.withIsRunningAsDesktopApplication(false)
.withIsNonProduction(false))
.withWindowAccessor(() => createWindowWithLogger())
.build(),
},
{
description: 'unit/integration tests environment',
build: (b, expectedLogger) => b
.withNoopLoggerFactory(() => expectedLogger)
.withEnvironment(new RuntimeEnvironmentStub().withIsRunningAsDesktopApplication(true))
.withWindowAccessor(() => createWindowWithLogger(null))
.build(),
},
];
testCases.forEach(({ description, build }) => {
it(`creates correct logger for ${description}`, () => {
// arrange
const expectedLogger = new LoggerStub();
const factory = build(new ClientLoggerFactoryBuilder(), expectedLogger);
// act
const { logger } = factory;
// assert
expect(logger).to.equal(expectedLogger);
});
});
});
});
function createWindowWithLogger(logger: Logger | null = new LoggerStub()): Window {
return {
log: logger,
} as unknown as Window;
}
class ClientLoggerFactoryBuilder {
private environment: RuntimeEnvironment = new RuntimeEnvironmentStub();
private windowAccessor: WindowAccessor = () => ({} as Window);
private noopLoggerFactory: LoggerCreationFunction = () => new LoggerStub();
private windowInjectedLoggerFactory: LoggerCreationFunction = () => new LoggerStub();
private consoleLoggerFactory: LoggerCreationFunction = () => new LoggerStub();
public withWindowAccessor(windowAccessor: WindowAccessor): this {
this.windowAccessor = windowAccessor;
return this;
}
public withEnvironment(environment: RuntimeEnvironment): this {
this.environment = environment;
return this;
}
public withNoopLoggerFactory(factory: LoggerCreationFunction): this {
this.noopLoggerFactory = factory;
return this;
}
public withWindowInjectedLoggerFactory(factory: LoggerCreationFunction): this {
this.windowInjectedLoggerFactory = factory;
return this;
}
public withConsoleLoggerFactory(factory: LoggerCreationFunction): this {
this.consoleLoggerFactory = factory;
return this;
}
public build(): ClientLoggerFactory {
return new TestableClientLoggerFactory(
this.environment,
this.windowAccessor,
this.noopLoggerFactory,
this.windowInjectedLoggerFactory,
this.consoleLoggerFactory,
);
}
}
class TestableClientLoggerFactory extends ClientLoggerFactory {
public constructor(
environment: RuntimeEnvironment,
windowAccessor: WindowAccessor,
noopLoggerFactory: LoggerCreationFunction,
windowInjectedLoggerFactory: LoggerCreationFunction,
consoleLoggerFactory: LoggerCreationFunction,
) {
super(
environment,
windowAccessor,
noopLoggerFactory,
windowInjectedLoggerFactory,
consoleLoggerFactory,
);
}
}