Files
privacy.sexy/tests/unit/infrastructure/RuntimeEnvironment/WindowVariablesValidator.spec.ts
undergroundwires 08dbfead7c Centralize log file and refactor desktop logging
- Migrate to `electron-log` v5.X.X, centralizing log files to adhere to
  best-practices.
- Add critical event logging in the log file.
- Replace `ElectronLog` type with `LogFunctions` for better abstraction.
- Unify log handling in `desktop-runtime-error` by removing
  `renderer.log` due to `electron-log` v5 changes.
- Update and extend logger interfaces, removing 'I' prefix and adding
  common log levels to abstract `electron-log` completely.
- Move logger interfaces to the application layer as it's cross-cutting
  concern, meanwhile keeping the implementations in the infrastructure
  layer.
- Introduce `useLogger` hook for easier logging in Vue components.
- Simplify `WindowVariables` by removing nullable properties.
- Improve documentation to clearly differentiate between desktop and web
  versions, outlining specific features of each.
2023-12-02 11:50:25 +01:00

228 lines
7.1 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { validateWindowVariables } from '@/infrastructure/WindowVariables/WindowVariablesValidator';
import { WindowVariables } from '@/infrastructure/WindowVariables/WindowVariables';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { SystemOperationsStub } from '@tests/unit/shared/Stubs/SystemOperationsStub';
import { getAbsentObjectTestCases } from '@tests/unit/shared/TestCases/AbsentTests';
import { WindowVariablesStub } from '@tests/unit/shared/Stubs/WindowVariablesStub';
describe('WindowVariablesValidator', () => {
describe('validateWindowVariables', () => {
describe('validates window type', () => {
itEachInvalidObjectValue((invalidObjectValue) => {
// arrange
const expectedError = 'window is not an object';
const window: Partial<WindowVariables> = invalidObjectValue as never;
// act
const act = () => validateWindowVariables(window);
// assert
expect(act).to.throw(expectedError);
});
});
describe('property validations', () => {
it('throws an error with a description of all invalid properties', () => {
// arrange
const invalidOs = 'invalid' as unknown as OperatingSystem;
const invalidIsDesktop = 'not a boolean' as unknown as boolean;
const expectedError = getExpectedError(
{
name: 'os',
object: invalidOs,
},
{
name: 'isDesktop',
object: invalidIsDesktop,
},
);
const input = new WindowVariablesStub()
.withOs(invalidOs)
.withIsDesktop(invalidIsDesktop);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.throw(expectedError);
});
describe('`os` property', () => {
it('throws an error when os is not a number', () => {
// arrange
const invalidOs = 'Linux' as unknown as OperatingSystem;
const expectedError = getExpectedError(
{
name: 'os',
object: invalidOs,
},
);
const input = new WindowVariablesStub()
.withOs(invalidOs);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.throw(expectedError);
});
it('throws an error for an invalid numeric os value', () => {
// arrange
const invalidOs = Number.MAX_SAFE_INTEGER;
const expectedError = getExpectedError(
{
name: 'os',
object: invalidOs,
},
);
const input = new WindowVariablesStub()
.withOs(invalidOs);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.throw(expectedError);
});
it('does not throw for a missing os value', () => {
// arrange
const input = new WindowVariablesStub()
.withIsDesktop(true)
.withOs(undefined);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.not.throw();
});
});
describe('`isDesktop` property', () => {
it('throws an error when only isDesktop is provided and it is true without a system object', () => {
// arrange
const systemObject = undefined;
const expectedError = getExpectedError(
{
name: 'system',
object: systemObject,
},
);
const input = new WindowVariablesStub()
.withIsDesktop(true)
.withSystem(systemObject);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.throw(expectedError);
});
it('does not throw when isDesktop is true with a valid system object', () => {
// arrange
const validSystem = new SystemOperationsStub();
const input = new WindowVariablesStub()
.withIsDesktop(true)
.withSystem(validSystem);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.not.throw();
});
it('does not throw when isDesktop is false without a system object', () => {
// arrange
const absentSystem = undefined;
const input = new WindowVariablesStub()
.withIsDesktop(false)
.withSystem(absentSystem);
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.not.throw();
});
});
describe('`system` property', () => {
expectObjectOnDesktop('system');
});
describe('`log` property', () => {
expectObjectOnDesktop('log');
});
});
it('does not throw for a valid object', () => {
const input = new WindowVariablesStub();
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.not.throw();
});
});
});
function expectObjectOnDesktop<T>(key: keyof WindowVariables) {
describe('validates object type on desktop', () => {
itEachInvalidObjectValue((invalidObjectValue) => {
// arrange
const invalidObject = invalidObjectValue as T;
const expectedError = getExpectedError({
name: key,
object: invalidObject,
});
const input: WindowVariables = {
...new WindowVariablesStub(),
isDesktop: true,
[key]: invalidObject,
};
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.throw(expectedError);
});
});
describe('does not object type when not on desktop', () => {
itEachInvalidObjectValue((invalidObjectValue) => {
// arrange
const isOnDesktop = false;
const invalidObject = invalidObjectValue as T;
const input: WindowVariables = {
...new WindowVariablesStub(),
isDesktop: isOnDesktop,
[key]: invalidObject,
};
// act
const act = () => validateWindowVariables(input);
// assert
expect(act).to.not.throw();
});
});
}
function itEachInvalidObjectValue<T>(runner: (invalidObjectValue: T) => void) {
const testCases: Array<{
readonly name: string;
readonly value: T;
}> = [
{
name: 'given string',
value: 'invalid object' as unknown as T,
},
{
name: 'given array of objects',
value: [{}, {}] as unknown as T,
},
...getAbsentObjectTestCases().map((testCase) => ({
name: `given absent: ${testCase.valueName}`,
value: testCase.absentValue as unknown as T,
})),
];
testCases.forEach((testCase) => {
it(testCase.name, () => {
runner(testCase.value);
});
});
}
function getExpectedError(...unexpectedObjects: Array<{
readonly name: keyof WindowVariables;
readonly object: unknown;
}>) {
const errors = unexpectedObjects
.map(({ name, object }) => `Unexpected ${name} (${typeof object})`);
return errors.join('\n');
}