This commit upgrades TypeScript from 5.4 to 5.5 and enables the
`noImplicitAny` option for stricter type checking. It refactors code to
comply with `noImplicitAny` and adapts to new TypeScript features and
limitations.
Key changes:
- Migrate from TypeScript 5.4 to 5.5
- Enable `noImplicitAny` for stricter type checking
- Refactor code to comply with new TypeScript features and limitations
Other supporting changes:
- Refactor progress bar handling for type safety
- Drop 'I' prefix from interfaces to align with new code convention
- Update TypeScript target from `ES2017` and `ES2018`.
This allows named capturing groups. Otherwise, new TypeScript compiler
does not compile the project and shows the following error:
```
...
TimestampedFilenameGenerator.spec.ts:105:23 - error TS1503: Named capturing groups are only available when targeting 'ES2018' or later
const pattern = /^(?<timestamp>\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-(?<scriptName>[^.]+?)(?:\.(?<extension>[^.]+))?$/;// timestamp-scriptName.extension
...
```
- Refactor usage of `electron-progressbar` for type safety and
less complexity.
295 lines
13 KiB
TypeScript
295 lines
13 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { nextTick, watch } from 'vue';
|
|
import { type SelectionModifier, useUserSelectionState } from '@/presentation/components/Shared/Hooks/UseUserSelectionState';
|
|
import type { UserSelection } from '@/application/Context/State/Selection/UserSelection';
|
|
import { UseCollectionStateStub } from '@tests/unit/shared/Stubs/UseCollectionStateStub';
|
|
import { UseAutoUnsubscribedEventsStub } from '@tests/unit/shared/Stubs/UseAutoUnsubscribedEventsStub';
|
|
import { UserSelectionStub } from '@tests/unit/shared/Stubs/UserSelectionStub';
|
|
import { ScriptStub } from '@tests/unit/shared/Stubs/ScriptStub';
|
|
import { CategoryCollectionStateStub } from '@tests/unit/shared/Stubs/CategoryCollectionStateStub';
|
|
import { SelectedScriptStub } from '@tests/unit/shared/Stubs/SelectedScriptStub';
|
|
import { ScriptSelectionStub } from '@tests/unit/shared/Stubs/ScriptSelectionStub';
|
|
import type { SelectedScript } from '@/application/Context/State/Selection/Script/SelectedScript';
|
|
|
|
describe('useUserSelectionState', () => {
|
|
describe('currentSelection', () => {
|
|
it('initializes with correct selection', () => {
|
|
// arrange
|
|
const expectedSelection = new UserSelectionStub();
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(new CategoryCollectionStateStub().withSelection(expectedSelection));
|
|
// act
|
|
const { returnObject } = runHook({
|
|
useCollectionState: collectionStateStub,
|
|
});
|
|
// assert
|
|
const actualSelection = returnObject.currentSelection.value;
|
|
expect(actualSelection).to.equal(expectedSelection);
|
|
});
|
|
describe('once collection state is changed', () => {
|
|
it('updated', () => {
|
|
// arrange
|
|
const initialSelection = new UserSelectionStub();
|
|
const changedSelection = new UserSelectionStub();
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(new CategoryCollectionStateStub().withSelection(initialSelection));
|
|
const { returnObject } = runHook({
|
|
useCollectionState: collectionStateStub,
|
|
});
|
|
// act
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: new CategoryCollectionStateStub().withSelection(changedSelection),
|
|
immediateOnly: false,
|
|
});
|
|
// assert
|
|
const actualSelection = returnObject.currentSelection.value;
|
|
expect(actualSelection).to.equal(changedSelection);
|
|
});
|
|
it('not updated when old state changes', async () => {
|
|
// arrange
|
|
const oldScriptSelection = new ScriptSelectionStub();
|
|
const oldSelectionState = new UserSelectionStub().withScripts(oldScriptSelection);
|
|
const newSelectionState = new UserSelectionStub();
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(new CategoryCollectionStateStub().withSelection(oldSelectionState));
|
|
const { returnObject } = runHook({
|
|
useCollectionState: collectionStateStub,
|
|
});
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: new CategoryCollectionStateStub().withSelection(newSelectionState),
|
|
immediateOnly: false,
|
|
});
|
|
let totalUpdates = 0;
|
|
watch(returnObject.currentSelection, () => {
|
|
totalUpdates++;
|
|
});
|
|
// act
|
|
oldScriptSelection.triggerSelectionChangedEvent([
|
|
new SelectedScriptStub(new ScriptStub('newInOldState')),
|
|
]);
|
|
await nextTick();
|
|
// assert
|
|
expect(totalUpdates).to.equal(0);
|
|
});
|
|
describe('triggers change', () => {
|
|
it('with new selection reference', async () => {
|
|
// arrange
|
|
const oldSelection = new UserSelectionStub();
|
|
const newSelection = new UserSelectionStub();
|
|
const initialCollectionState = new CategoryCollectionStateStub()
|
|
.withSelection(oldSelection);
|
|
const changedCollectionState = new CategoryCollectionStateStub()
|
|
.withSelection(newSelection);
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(initialCollectionState);
|
|
const { returnObject } = runHook({ useCollectionState: collectionStateStub });
|
|
let isChangeTriggered = false;
|
|
watch(returnObject.currentSelection, () => {
|
|
isChangeTriggered = true;
|
|
});
|
|
// act
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: changedCollectionState,
|
|
immediateOnly: false,
|
|
});
|
|
await nextTick();
|
|
// assert
|
|
expect(isChangeTriggered).to.equal(true);
|
|
});
|
|
it('with the same selection reference', async () => {
|
|
// arrange
|
|
const userSelection = new UserSelectionStub();
|
|
const initialCollectionState = new CategoryCollectionStateStub()
|
|
.withSelection(userSelection);
|
|
const changedCollectionState = new CategoryCollectionStateStub()
|
|
.withSelection(userSelection);
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(initialCollectionState);
|
|
const { returnObject } = runHook({ useCollectionState: collectionStateStub });
|
|
let isChangeTriggered = false;
|
|
watch(returnObject.currentSelection, () => {
|
|
isChangeTriggered = true;
|
|
});
|
|
// act
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: changedCollectionState,
|
|
immediateOnly: false,
|
|
});
|
|
await nextTick();
|
|
// assert
|
|
expect(isChangeTriggered).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
describe('once selection state is changed', () => {
|
|
it('updated with same collection state', async () => {
|
|
// arrange
|
|
const initialScripts = [
|
|
new SelectedScriptStub(new ScriptStub('initialSelectedScript')),
|
|
];
|
|
const changedScripts = [
|
|
new SelectedScriptStub(new ScriptStub('changedSelectedScript')),
|
|
];
|
|
const scriptSelectionStub = new ScriptSelectionStub()
|
|
.withSelectedScripts(initialScripts);
|
|
const expectedSelectionState = new UserSelectionStub().withScripts(scriptSelectionStub);
|
|
const collectionState = new CategoryCollectionStateStub()
|
|
.withSelection(expectedSelectionState);
|
|
const collectionStateStub = new UseCollectionStateStub().withState(collectionState);
|
|
const { returnObject } = runHook({
|
|
useCollectionState: collectionStateStub,
|
|
});
|
|
// act
|
|
scriptSelectionStub.triggerSelectionChangedEvent(changedScripts);
|
|
await nextTick();
|
|
// assert
|
|
const actualSelection = returnObject.currentSelection.value;
|
|
expect(actualSelection).to.equal(expectedSelectionState);
|
|
});
|
|
it('updated once collection state is changed', async () => {
|
|
// arrange
|
|
const changedScripts = [
|
|
new SelectedScriptStub(new ScriptStub('changedSelectedScript')),
|
|
];
|
|
const scriptSelectionStub = new ScriptSelectionStub();
|
|
const newSelectionState = new UserSelectionStub().withScripts(scriptSelectionStub);
|
|
const initialCollectionState = new CategoryCollectionStateStub().withSelectedScripts([
|
|
new SelectedScriptStub(new ScriptStub('initialSelectedScriptInInitialCollection')),
|
|
]);
|
|
const collectionStateStub = new UseCollectionStateStub().withState(initialCollectionState);
|
|
const { returnObject } = runHook({ useCollectionState: collectionStateStub });
|
|
// act
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: new CategoryCollectionStateStub().withSelection(newSelectionState),
|
|
immediateOnly: false,
|
|
});
|
|
scriptSelectionStub.triggerSelectionChangedEvent(changedScripts);
|
|
// assert
|
|
const actualSelection = returnObject.currentSelection.value;
|
|
expect(actualSelection).to.equal(newSelectionState);
|
|
});
|
|
describe('triggers change', () => {
|
|
it('with new selected scripts array reference', async () => {
|
|
// arrange
|
|
const oldSelectedScriptsArrayReference = new Array<SelectedScript>();
|
|
const newSelectedScriptsArrayReference = new Array<SelectedScript>();
|
|
const scriptSelectionStub = new ScriptSelectionStub()
|
|
.withSelectedScripts(oldSelectedScriptsArrayReference);
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(new CategoryCollectionStateStub().withSelection(
|
|
new UserSelectionStub().withScripts(scriptSelectionStub),
|
|
));
|
|
const { returnObject } = runHook({ useCollectionState: collectionStateStub });
|
|
let isChangeTriggered = false;
|
|
watch(returnObject.currentSelection, () => {
|
|
isChangeTriggered = true;
|
|
});
|
|
// act
|
|
scriptSelectionStub.triggerSelectionChangedEvent(newSelectedScriptsArrayReference);
|
|
await nextTick();
|
|
// assert
|
|
expect(isChangeTriggered).to.equal(true);
|
|
});
|
|
it('with same selected scripts array reference', async () => {
|
|
// arrange
|
|
const sharedSelectedScriptsReference = new Array<SelectedScript>();
|
|
const scriptSelectionStub = new ScriptSelectionStub()
|
|
.withSelectedScripts(sharedSelectedScriptsReference);
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(new CategoryCollectionStateStub().withSelection(
|
|
new UserSelectionStub().withScripts(scriptSelectionStub),
|
|
));
|
|
const { returnObject } = runHook({ useCollectionState: collectionStateStub });
|
|
let isChangeTriggered = false;
|
|
watch(returnObject.currentSelection, () => {
|
|
isChangeTriggered = true;
|
|
});
|
|
// act
|
|
scriptSelectionStub.triggerSelectionChangedEvent(sharedSelectedScriptsReference);
|
|
await nextTick();
|
|
// assert
|
|
expect(isChangeTriggered).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
describe('modifyCurrentSelection', () => {
|
|
it('should modify current state', () => {
|
|
// arrange
|
|
const { returnObject, collectionStateStub } = runHook();
|
|
const expectedSelection = collectionStateStub.state.selection;
|
|
let mutatedSelection: UserSelection | undefined;
|
|
const mutator: SelectionModifier = (selection) => {
|
|
mutatedSelection = selection;
|
|
};
|
|
// act
|
|
returnObject.modifyCurrentSelection(mutator);
|
|
// assert
|
|
expect(collectionStateStub.isStateModified()).to.equal(true);
|
|
expect(mutatedSelection).to.equal(expectedSelection);
|
|
});
|
|
it('new state is modified once collection state is changed', async () => {
|
|
// arrange
|
|
const { returnObject, collectionStateStub } = runHook();
|
|
const expectedSelection = new UserSelectionStub();
|
|
const newCollectionState = new CategoryCollectionStateStub()
|
|
.withSelection(expectedSelection);
|
|
let mutatedSelection: UserSelection | undefined;
|
|
const mutator: SelectionModifier = (selection) => {
|
|
mutatedSelection = selection;
|
|
};
|
|
// act
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: newCollectionState,
|
|
immediateOnly: false,
|
|
});
|
|
await nextTick();
|
|
returnObject.modifyCurrentSelection(mutator);
|
|
// assert
|
|
expect(collectionStateStub.isStateModified()).to.equal(true);
|
|
expect(mutatedSelection).to.equal(expectedSelection);
|
|
});
|
|
it('old state is not modified once collection state is changed', async () => {
|
|
// arrange
|
|
const oldState = new CategoryCollectionStateStub().withSelectedScripts([
|
|
new SelectedScriptStub(new ScriptStub('scriptFromOldState')),
|
|
]);
|
|
const collectionStateStub = new UseCollectionStateStub()
|
|
.withState(oldState);
|
|
const { returnObject } = runHook({ useCollectionState: collectionStateStub });
|
|
const expectedSelection = new UserSelectionStub();
|
|
const newCollectionState = new CategoryCollectionStateStub()
|
|
.withSelection(expectedSelection);
|
|
let totalMutations = 0;
|
|
const mutator: SelectionModifier = () => {
|
|
totalMutations++;
|
|
};
|
|
// act
|
|
collectionStateStub.triggerOnStateChange({
|
|
newState: newCollectionState,
|
|
immediateOnly: false,
|
|
});
|
|
await nextTick();
|
|
returnObject.modifyCurrentSelection(mutator);
|
|
// assert
|
|
expect(totalMutations).to.equal(1);
|
|
});
|
|
});
|
|
});
|
|
|
|
function runHook(scenario?: {
|
|
useCollectionState?: UseCollectionStateStub,
|
|
}) {
|
|
const collectionStateStub = scenario?.useCollectionState ?? new UseCollectionStateStub();
|
|
const eventsStub = new UseAutoUnsubscribedEventsStub();
|
|
const returnObject = useUserSelectionState(
|
|
collectionStateStub.get(),
|
|
eventsStub.get(),
|
|
);
|
|
return {
|
|
returnObject,
|
|
collectionStateStub,
|
|
eventsStub,
|
|
};
|
|
}
|