Files
privacy.sexy/tests/unit/presentation/components/Shared/ExpandCollapse/UseExpandCollapseAnimation.spec.ts
undergroundwires e17744faf0 Bump to TypeScript 5.5 and enable noImplicitAny
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.
2024-09-26 16:07:37 +02:00

99 lines
3.7 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
type AnimationFunction, TRANSITION_DURATION_MILLISECONDS,
useExpandCollapseAnimation, type MutatedStyleProperties,
} from '@/presentation/components/Shared/ExpandCollapse/UseExpandCollapseAnimation';
import { TimerStub } from '@tests/unit/shared/Stubs/TimerStub';
import { watchPromiseState, flushPromiseResolutionQueue } from '@tests/unit/shared/PromiseInspection';
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
import { indentText } from '@/application/Common/Text/IndentText';
describe('UseExpandCollapseAnimation', () => {
describe('useExpandCollapseAnimation', () => {
describe('collapse', () => {
describe('animations', () => {
runSharedTestsForAnimation((hook) => hook.collapse);
});
});
describe('expand', () => {
describe('animations', () => {
runSharedTestsForAnimation((hook) => hook.expand);
});
});
});
});
function runSharedTestsForAnimation(
getAnimator: (hookResult: ReturnType<typeof useExpandCollapseAnimation>) => AnimationFunction,
) {
it('completes after transition duration', async () => {
// arrange
const timer = new TimerStub();
const element = createElementMock();
const passedDurationInMs = TRANSITION_DURATION_MILLISECONDS;
const hookResult = useExpandCollapseAnimation(timer);
const animator = getAnimator(hookResult);
// act
const promiseState = watchPromiseState(animator(element));
timer.tickNext(passedDurationInMs);
await flushPromiseResolutionQueue();
// assert
expect(promiseState.isPending()).to.equal(true);
});
it('remains unresolved before transition duration', async () => {
// arrange
const timer = new TimerStub();
const element = createElementMock();
const passedDurationInMs = TRANSITION_DURATION_MILLISECONDS / 2;
const hookResult = useExpandCollapseAnimation(timer);
const animator = getAnimator(hookResult);
// act
const promiseState = watchPromiseState(animator(element));
timer.tickNext(passedDurationInMs);
await flushPromiseResolutionQueue();
// assert
expect(promiseState.isFulfilled()).to.equal(false);
});
it('restores original styles post-animation', async () => {
// arrange
const expectedStyleValues: MutatedStyleProperties = {
height: 'auto',
overflow: 'scroll',
paddingBottom: '5px',
paddingTop: '5px',
transition: 'all',
visibility: 'visible',
display: 'inline-block',
};
const element = document.createElement('div');
Object.entries(expectedStyleValues).forEach(([key, value]) => {
element.style[key as keyof MutatedStyleProperties] = value;
});
const timer = new TimerStub();
const hookResult = useExpandCollapseAnimation(timer);
const animator = getAnimator(hookResult);
// act
const promise = animator(element);
timer.tickNext(TRANSITION_DURATION_MILLISECONDS);
await promise;
// assert
Object.entries(expectedStyleValues).forEach(([key, expectedStyleValue]) => {
const styleProperty = key as keyof MutatedStyleProperties;
const actualStyleValue = element.style[styleProperty];
expect(actualStyleValue).to.equal(expectedStyleValue, formatAssertionMessage([
`Style key: ${key}`,
`Expected style value: ${expectedStyleValue}`,
`Actual style value: ${actualStyleValue}`,
`Initial style value: ${expectedStyleValues}`,
'All styles:',
...Object.entries(expectedStyleValues)
.map(([k, value]) => indentText(`- ${k} > actual: "${actualStyleValue}" | expected: "${value}"`)),
]));
});
});
}
function createElementMock(): HTMLElement {
return document.createElement('div');
}