This commit applies `strictNullChecks` to the entire codebase to improve maintainability and type safety. Key changes include: - Remove some explicit null-checks where unnecessary. - Add necessary null-checks. - Refactor static factory functions for a more functional approach. - Improve some test names and contexts for better debugging. - Add unit tests for any additional logic introduced. - Refactor `createPositionFromRegexFullMatch` to its own function as the logic is reused. - Prefer `find` prefix on functions that may return `undefined` and `get` prefix for those that always return a value.
89 lines
3.0 KiB
TypeScript
89 lines
3.0 KiB
TypeScript
import { it, expect } from 'vitest';
|
|
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
|
import { CategoryCollectionStub } from '@tests/unit/shared/Stubs/CategoryCollectionStub';
|
|
import { CategoryStub } from '@tests/unit/shared/Stubs/CategoryStub';
|
|
import { UserSelection } from '@/application/Context/State/Selection/UserSelection';
|
|
import { IScript } from '@/domain/IScript';
|
|
|
|
export class UserSelectionTestRunner {
|
|
private readonly collection = new CategoryCollectionStub();
|
|
|
|
private existingScripts: readonly SelectedScript[] = [];
|
|
|
|
private events: Array<readonly SelectedScript[]> = [];
|
|
|
|
private sut: UserSelection;
|
|
|
|
public withCategory(categoryId: number, scripts: readonly IScript[]) {
|
|
const category = new CategoryStub(categoryId)
|
|
.withScripts(...scripts);
|
|
this.collection
|
|
.withAction(category);
|
|
return this;
|
|
}
|
|
|
|
public withSelectedScripts(existingScripts: readonly SelectedScript[]) {
|
|
this.existingScripts = existingScripts;
|
|
return this;
|
|
}
|
|
|
|
public run(runner?: (sut: UserSelection) => void) {
|
|
this.sut = this.createSut();
|
|
if (runner) {
|
|
runner(this.sut);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public expectTotalFiredEvents(amount: number) {
|
|
const testName = amount === 0 ? 'does not fire changed event' : `fires changed event ${amount} times`;
|
|
it(testName, () => {
|
|
expect(this.events).to.have.lengthOf(amount);
|
|
});
|
|
return this;
|
|
}
|
|
|
|
public expectFinalScripts(finalScripts: readonly SelectedScript[]) {
|
|
expectSameScripts(finalScripts, this.sut.selectedScripts);
|
|
return this;
|
|
}
|
|
|
|
public expectFinalScriptsInEvent(eventIndex: number, finalScripts: readonly SelectedScript[]) {
|
|
expectSameScripts(this.events[eventIndex], finalScripts);
|
|
return this;
|
|
}
|
|
|
|
private createSut(): UserSelection {
|
|
const sut = new UserSelection(this.collection, this.existingScripts);
|
|
sut.changed.on((s) => this.events.push(s));
|
|
return sut;
|
|
}
|
|
}
|
|
|
|
function expectSameScripts(actual: readonly SelectedScript[], expected: readonly SelectedScript[]) {
|
|
it('has same expected scripts', () => {
|
|
const existingScriptIds = expected.map((script) => script.id).sort();
|
|
const expectedScriptIds = actual.map((script) => script.id).sort();
|
|
expect(existingScriptIds).to.deep.equal(expectedScriptIds);
|
|
});
|
|
it('has expected revert state', () => {
|
|
const scriptsWithDifferentStatus = actual
|
|
.filter((script) => {
|
|
const other = expected.find((existing) => existing.id === script.id);
|
|
if (!other) {
|
|
throw new Error(`Script "${script.id}" does not exist in expected scripts: ${JSON.stringify(expected, null, '\t')}`);
|
|
}
|
|
return script.revert !== other.revert;
|
|
});
|
|
expect(scriptsWithDifferentStatus).to.have.lengthOf(
|
|
0,
|
|
`Scripts with different statuses:\n${
|
|
scriptsWithDifferentStatus
|
|
.map((s) => `[id: ${s.id}, actual status: ${s.revert}, `
|
|
+ `expected status: ${expected.find((existing) => existing.id === s.id)?.revert ?? 'unknown'}]`)
|
|
.join(' , ')
|
|
}`,
|
|
);
|
|
});
|
|
}
|