This commit upgrades TypeScript to the latest version 5.3 and introduces `verbatimModuleSyntax` in line with the official Vue guide recommendatinos (vuejs/docs#2592). By enforcing `import type` for type-only imports, this commit improves code clarity and supports tooling optimization, ensuring imports are only bundled when necessary for runtime. Changes: - Bump TypeScript to 5.3.3 across the project. - Adjust import statements to utilize `import type` where applicable, promoting cleaner and more efficient code.
131 lines
4.5 KiB
TypeScript
131 lines
4.5 KiB
TypeScript
import { expect } from 'vitest';
|
|
import type { ScriptSelection } from '@/application/Context/State/Selection/Script/ScriptSelection';
|
|
import type { SelectedScript } from '@/application/Context/State/Selection/Script/SelectedScript';
|
|
import type { IScript } from '@/domain/IScript';
|
|
import type { ScriptSelectionChange, ScriptSelectionChangeCommand } from '@/application/Context/State/Selection/Script/ScriptSelectionChange';
|
|
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
|
|
import { StubWithObservableMethodCalls } from './StubWithObservableMethodCalls';
|
|
import { EventSourceStub } from './EventSourceStub';
|
|
import { SelectedScriptStub } from './SelectedScriptStub';
|
|
|
|
export class ScriptSelectionStub
|
|
extends StubWithObservableMethodCalls<ScriptSelection>
|
|
implements ScriptSelection {
|
|
public readonly changed = new EventSourceStub<readonly SelectedScript[]>();
|
|
|
|
public selectedScripts: readonly SelectedScript[] = [];
|
|
|
|
public isSelectedResult: boolean | undefined;
|
|
|
|
public withSelectedScripts(selectedScripts: readonly SelectedScript[]): this {
|
|
this.selectedScripts = selectedScripts;
|
|
return this;
|
|
}
|
|
|
|
public triggerSelectionChangedEvent(scripts: readonly SelectedScript[]): this {
|
|
this.changed.notify(scripts);
|
|
return this;
|
|
}
|
|
|
|
public withIsSelectedResult(isSelected: boolean): this {
|
|
this.isSelectedResult = isSelected;
|
|
return this;
|
|
}
|
|
|
|
public isScriptSelected(scriptId: string, revert: boolean): boolean {
|
|
return this.isScriptChanged({
|
|
scriptId,
|
|
newStatus: {
|
|
isSelected: true,
|
|
isReverted: revert,
|
|
},
|
|
});
|
|
}
|
|
|
|
public isScriptDeselected(scriptId: string): boolean {
|
|
return this.isScriptChanged({
|
|
scriptId,
|
|
newStatus: {
|
|
isSelected: false,
|
|
},
|
|
});
|
|
}
|
|
|
|
public processChanges(action: ScriptSelectionChangeCommand): void {
|
|
this.registerMethodCall({
|
|
methodName: 'processChanges',
|
|
args: [action],
|
|
});
|
|
}
|
|
|
|
public selectOnly(scripts: ReadonlyArray<IScript>): void {
|
|
this.registerMethodCall({
|
|
methodName: 'selectOnly',
|
|
args: [scripts],
|
|
});
|
|
this.selectedScripts = scripts.map((s) => new SelectedScriptStub(s));
|
|
}
|
|
|
|
public selectAll(): void {
|
|
this.registerMethodCall({
|
|
methodName: 'selectAll',
|
|
args: [],
|
|
});
|
|
}
|
|
|
|
public deselectAll(): void {
|
|
this.registerMethodCall({
|
|
methodName: 'deselectAll',
|
|
args: [],
|
|
});
|
|
}
|
|
|
|
public isSelected(): boolean {
|
|
if (this.isSelectedResult === undefined) {
|
|
throw new Error('Method not configured.');
|
|
}
|
|
return this.isSelectedResult;
|
|
}
|
|
|
|
public assertSelectionChanges(expectedChanges: readonly ScriptSelectionChange[]): void {
|
|
const actualChanges = this.getAllChanges();
|
|
expect(actualChanges).to.have.lengthOf(expectedChanges.length, formatAssertionMessage([
|
|
`Expected number of changes to be ${expectedChanges.length}, but found ${actualChanges.length}`,
|
|
`Expected changes (${expectedChanges.length}):`, toNumberedPrettyJson(expectedChanges),
|
|
`Actual changes (${actualChanges.length}):`, toNumberedPrettyJson(actualChanges),
|
|
]));
|
|
const unexpectedChanges = actualChanges.filter(
|
|
(actual) => !expectedChanges.some((expected) => isSameChange(actual, expected)),
|
|
);
|
|
expect(unexpectedChanges).to.have.lengthOf(0, formatAssertionMessage([
|
|
`Found ${unexpectedChanges.length} unexpected changes.`,
|
|
'Unexpected changes:', toNumberedPrettyJson(unexpectedChanges),
|
|
'Expected changes:', toNumberedPrettyJson(expectedChanges),
|
|
'Actual changes:', toNumberedPrettyJson(actualChanges),
|
|
]));
|
|
}
|
|
|
|
private isScriptChanged(expectedChange: ScriptSelectionChange): boolean {
|
|
return this.getAllChanges().some((change) => isSameChange(change, expectedChange));
|
|
}
|
|
|
|
private getAllChanges(): ScriptSelectionChange[] {
|
|
const processChangesCalls = this.callHistory.filter((c) => c.methodName === 'processChanges');
|
|
const changeCommands = processChangesCalls.map(
|
|
(call) => call.args[0] as ScriptSelectionChangeCommand,
|
|
);
|
|
const changes = changeCommands.flatMap((command) => command.changes);
|
|
return changes;
|
|
}
|
|
}
|
|
|
|
function isSameChange(change: ScriptSelectionChange, otherChange: ScriptSelectionChange): boolean {
|
|
return change.newStatus.isSelected === otherChange.newStatus.isSelected
|
|
&& change.newStatus.isReverted === otherChange.newStatus.isReverted
|
|
&& change.scriptId === otherChange.scriptId;
|
|
}
|
|
|
|
function toNumberedPrettyJson<T>(array: readonly T[]): string {
|
|
return array.map((item, index) => `${index + 1}: ${JSON.stringify(item, undefined, 2)}`).join('\n');
|
|
}
|