Improve desktop runtime execution tests

Test improvements:

- Capture titles for all macOS windows, not just the frontmost.
- Incorporate missing application log files.
- Improve log clarity with enriched context.
- Improve application termination on macOS by reducing grace period.
- Ensure complete application termination on macOS.
- Validate Vue application loading through an initial log.
- Support ignoring environment-specific `stderr` errors.
- Do not fail the test if working directory cannot be deleted.
- Use retry pattern when installing dependencies due to network errors.

Refactorings:

- Migrate the test code to TypeScript.
- Replace deprecated `rmdir` with `rm` for error-resistant directory
  removal.
- Improve sanity checking by shifting from App.vue to Vue bootstrapper.
- Centralize environment variable management with `EnvironmentVariables`
  construct.
- Rename infrastructure/Environment to RuntimeEnvironment for clarity.
- Isolate WindowVariables and SystemOperations from RuntimeEnvironment.
- Inject logging via preloader.
- Correct mislabeled RuntimeSanity tests.

Configuration:

- Introduce `npm run check:desktop` for simplified execution.
- Omit `console.log` override due to `nodeIntegration` restrictions and
  reveal logging functionality using context-bridging.
This commit is contained in:
undergroundwires
2023-08-29 16:30:00 +02:00
parent 35be05df20
commit ad0576a752
146 changed files with 2418 additions and 1186 deletions

View File

@@ -0,0 +1,15 @@
import { describe, it } from 'vitest';
import { EnvironmentVariablesFactory } from '@/infrastructure/EnvironmentVariables/EnvironmentVariablesFactory';
describe('EnvironmentVariablesFactory', () => {
it('can read current environment', () => {
const environmentVariables = EnvironmentVariablesFactory.Current.instance;
Object.entries(environmentVariables).forEach(([key, value]) => {
it(`${key} value is defined`, () => {
expect(value).to.not.equal(undefined);
expect(value).to.not.equal(null);
expect(value).to.not.equal(Number.NaN);
});
});
});
});

View File

@@ -1,15 +1,16 @@
import { describe, it, expect } from 'vitest';
import { ViteAppMetadata } from '@/infrastructure/Metadata/Vite/ViteAppMetadata';
import packageJson from '@/../package.json' assert { type: 'json' };
import { PropertyKeys } from '@/TypeHelpers';
import { IAppMetadata } from '@/infrastructure/EnvironmentVariables/IAppMetadata';
import { ViteEnvironmentVariables } from '@/infrastructure/EnvironmentVariables/Vite/ViteEnvironmentVariables';
describe('ViteAppMetadata', () => {
describe('populates from package.json', () => {
describe('ViteEnvironmentVariables', () => {
describe('populates metadata from package.json', () => {
interface ITestCase {
readonly getActualValue: (sut: ViteAppMetadata) => string;
readonly getActualValue: (sut: IAppMetadata) => string;
readonly expected: string;
}
const testCases: { readonly [K in PropertyKeys<ViteAppMetadata>]: ITestCase } = {
const testCases: { readonly [K in PropertyKeys<IAppMetadata>]: ITestCase } = {
name: {
expected: packageJson.name,
getActualValue: (sut) => sut.name,
@@ -34,7 +35,7 @@ describe('ViteAppMetadata', () => {
Object.entries(testCases).forEach(([propertyName, { expected, getActualValue }]) => {
it(`should correctly get the value of ${propertyName}`, () => {
// arrange
const sut = new ViteAppMetadata();
const sut = new ViteEnvironmentVariables();
// act
const actualValue = getActualValue(sut);

View File

@@ -22,8 +22,8 @@ describe('SanityChecks', () => {
function generateTestOptions(): ISanityCheckOptions[] {
const defaultOptions: ISanityCheckOptions = {
validateMetadata: true,
validateEnvironment: true,
validateEnvironmentVariables: true,
validateWindowVariables: true,
};
return generateBooleanPermutations(defaultOptions);
}

View File

@@ -1,15 +0,0 @@
import { describe } from 'vitest';
import { EnvironmentValidator } from '@/infrastructure/RuntimeSanity/Validators/EnvironmentValidator';
import { FactoryFunction } from '@/infrastructure/RuntimeSanity/Common/FactoryValidator';
import { EnvironmentStub } from '@tests/unit/shared/Stubs/EnvironmentStub';
import { IEnvironment } from '@/infrastructure/Environment/IEnvironment';
import { runFactoryValidatorTests } from './FactoryValidatorConcreteTestRunner';
describe('EnvironmentValidator', () => {
runFactoryValidatorTests({
createValidator: (factory?: FactoryFunction<IEnvironment>) => new EnvironmentValidator(factory),
enablingOptionProperty: 'validateEnvironment',
factoryFunctionStub: () => new EnvironmentStub(),
expectedValidatorName: 'environment',
});
});

View File

@@ -0,0 +1,7 @@
import { describe } from 'vitest';
import { EnvironmentVariablesValidator } from '@/infrastructure/RuntimeSanity/Validators/EnvironmentVariablesValidator';
import { itNoErrorsOnCurrentEnvironment } from './ValidatorTestRunner';
describe('EnvironmentVariablesValidator', () => {
itNoErrorsOnCurrentEnvironment(() => new EnvironmentVariablesValidator());
});

View File

@@ -1,60 +0,0 @@
import { PropertyKeys } from '@/TypeHelpers';
import { FactoryFunction, FactoryValidator } from '@/infrastructure/RuntimeSanity/Common/FactoryValidator';
import { ISanityCheckOptions } from '@/infrastructure/RuntimeSanity/Common/ISanityCheckOptions';
import { SanityCheckOptionsStub } from '@tests/unit/shared/Stubs/SanityCheckOptionsStub';
interface ITestOptions<T> {
createValidator: (factory?: FactoryFunction<T>) => FactoryValidator<T>;
enablingOptionProperty: PropertyKeys<ISanityCheckOptions>;
factoryFunctionStub: FactoryFunction<T>;
expectedValidatorName: string;
}
export function runFactoryValidatorTests<T>(
testOptions: ITestOptions<T>,
) {
if (!testOptions) {
throw new Error('missing options');
}
describe('shouldValidate', () => {
it('returns true when option is true', () => {
// arrange
const expectedValue = true;
const options: ISanityCheckOptions = {
...new SanityCheckOptionsStub(),
[testOptions.enablingOptionProperty]: true,
};
const validatorUnderTest = testOptions.createValidator(testOptions.factoryFunctionStub);
// act
const actualValue = validatorUnderTest.shouldValidate(options);
// assert
expect(actualValue).to.equal(expectedValue);
});
it('returns false when option is false', () => {
// arrange
const expectedValue = false;
const options: ISanityCheckOptions = {
...new SanityCheckOptionsStub(),
[testOptions.enablingOptionProperty]: false,
};
const validatorUnderTest = testOptions.createValidator(testOptions.factoryFunctionStub);
// act
const actualValue = validatorUnderTest.shouldValidate(options);
// assert
expect(actualValue).to.equal(expectedValue);
});
});
describe('name', () => {
it('returns as expected', () => {
// arrange
const expectedName = testOptions.expectedValidatorName;
// act
const validatorUnderTest = testOptions.createValidator(testOptions.factoryFunctionStub);
// assert
const actualName = validatorUnderTest.name;
expect(actualName).to.equal(expectedName);
});
});
}

View File

@@ -1,15 +0,0 @@
import { describe } from 'vitest';
import { MetadataValidator } from '@/infrastructure/RuntimeSanity/Validators/MetadataValidator';
import { FactoryFunction } from '@/infrastructure/RuntimeSanity/Common/FactoryValidator';
import { AppMetadataStub } from '@tests/unit/shared/Stubs/AppMetadataStub';
import { IAppMetadata } from '@/infrastructure/Metadata/IAppMetadata';
import { runFactoryValidatorTests } from './FactoryValidatorConcreteTestRunner';
describe('MetadataValidator', () => {
runFactoryValidatorTests({
createValidator: (factory?: FactoryFunction<IAppMetadata>) => new MetadataValidator(factory),
enablingOptionProperty: 'validateMetadata',
factoryFunctionStub: () => new AppMetadataStub(),
expectedValidatorName: 'metadata',
});
});

View File

@@ -0,0 +1,18 @@
import { it, expect } from 'vitest';
import { ISanityValidator } from '@/infrastructure/RuntimeSanity/Common/ISanityValidator';
export function itNoErrorsOnCurrentEnvironment(
factory: () => ISanityValidator,
) {
if (!factory) {
throw new Error('missing factory');
}
it('it does report errors on current environment', () => {
// arrange
const validator = factory();
// act
const errors = [...validator.collectErrors()];
// assert
expect(errors).to.have.lengthOf(0);
});
}

View File

@@ -0,0 +1,7 @@
import { describe } from 'vitest';
import { WindowVariablesValidator } from '@/infrastructure/RuntimeSanity/Validators/WindowVariablesValidator';
import { itNoErrorsOnCurrentEnvironment } from './ValidatorTestRunner';
describe('WindowVariablesValidator', () => {
itNoErrorsOnCurrentEnvironment(() => new WindowVariablesValidator());
});