diff --git a/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/LogMessageUtils.ts b/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/LogMessageUtils.ts index 07f8adca9581..2bfdfc60aa93 100644 --- a/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/LogMessageUtils.ts +++ b/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/LogMessageUtils.ts @@ -1,4 +1,4 @@ -import { ComparisonMode, TestValue } from './types'; +import { TestValue } from './types'; export const RUNTIME_TEST_ERRORS = { UNDEFINED_TEST_SUITE: 'Undefined test suite context', @@ -26,14 +26,3 @@ export function color( return `${COLOR_CODES[color]}${value}\x1b[0m`; } - -export function defaultTestErrorLog( - expected: TestValue, - received: TestValue, - mode: ComparisonMode -) { - const coloredExpected = color(expected, 'green'); - const coloredReceived = color(received, 'red'); - const coloredMode = color(mode, 'yellow'); - return `Expected ${coloredExpected} received ${coloredReceived}, mode: ${coloredMode}`; -} diff --git a/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/Matchers.ts b/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/Matchers.ts index 6cc8b644090c..dc96485ca318 100644 --- a/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/Matchers.ts +++ b/app/src/examples/RuntimeTests/ReanimatedRuntimeTestsRunner/Matchers.ts @@ -1,5 +1,5 @@ import { getComparator } from './Comparators'; -import { color, defaultTestErrorLog } from './LogMessageUtils'; +import { color } from './LogMessageUtils'; import { ComparisonMode, OperationUpdate, @@ -8,10 +8,20 @@ import { TrackerCallCount, } from './types'; +type MatcherFunction = ( + currentValue: TestValue, + expectedValue: TestValue, + ...additionalArgs: Array +) => { + pass: boolean; + message: string; +}; + export class Matchers { - constructor(private currentValue: TestValue, private testCase: TestCase) {} + private _negation = false; + constructor(private _currentValue: TestValue, private _testCase: TestCase) {} - private assertValueIsCallTracker( + private static _assertValueIsCallTracker( value: TrackerCallCount | TestValue ): asserts value is TrackerCallCount { if ( @@ -22,56 +32,111 @@ export class Matchers { } } - public toBe(expectedValue: TestValue, comparisonMode = ComparisonMode.AUTO) { + private _toBeMatcher: MatcherFunction = ( + currentValue: TestValue, + expectedValue: TestValue, + comparisonModeUnknown: unknown + ) => { + const comparisonMode: ComparisonMode = + typeof comparisonModeUnknown === 'string' && + comparisonModeUnknown in ComparisonMode + ? (comparisonModeUnknown as ComparisonMode) + : ComparisonMode.AUTO; + const isEqual = getComparator(comparisonMode); - if (!isEqual(expectedValue, this.currentValue)) { - this.testCase.errors.push( - defaultTestErrorLog(expectedValue, this.currentValue, comparisonMode) - ); - } - } - public toBeCalled(times = 1) { - this.assertValueIsCallTracker(this.currentValue); - const callsCount = this.currentValue.onUI + this.currentValue.onJS; - if (callsCount !== times) { - const name = color(this.currentValue.name, 'green'); - const expected = color(times, 'green'); - const received = color(callsCount, 'red'); - this.testCase.errors.push( - `Expected ${name} to be called ${expected} times, but was called ${received} times` - ); - } - } + const coloredExpected = color(expectedValue, 'green'); + const coloredReceived = color(currentValue, 'red'); + const coloredMode = color(comparisonMode, 'yellow'); + + return { + pass: isEqual(expectedValue, currentValue), + message: `Expected${ + this._negation ? ' NOT' : '' + } ${coloredExpected} received ${coloredReceived}, mode: ${coloredMode}`, + }; + }; + + private _toBeCalledMatcher: MatcherFunction = ( + currentValue: TestValue, + times = 1 + ) => { + Matchers._assertValueIsCallTracker(currentValue); + const callsCount = currentValue.onUI + currentValue.onJS; + const name = color(currentValue.name, 'green'); + const expected = color(times, 'green'); + const received = color(callsCount, 'red'); + return { + pass: callsCount === times, + message: `Expected ${name}${ + this._negation ? ' NOT' : '' + } to be called ${expected} times, but was called ${received} times`, + }; + }; - public toBeCalledUI(times = 1) { - this.assertValueIsCallTracker(this.currentValue); - if (this.currentValue.onUI !== times) { - const name = color(this.currentValue.name, 'green'); - const threadName = color('UI thread', 'cyan'); - const expected = color(times, 'green'); - const received = color(this.currentValue.onUI, 'red'); - this.testCase.errors.push( - `Expected ${name} to be called ${expected} times on ${threadName}, but was called ${received} times` + private _toBeCalledUIMatcher: MatcherFunction = ( + currentValue: TestValue, + times = 1 + ) => { + Matchers._assertValueIsCallTracker(currentValue); + const callsCount = currentValue.onUI; + const name = color(currentValue.name, 'green'); + const threadName = color('UI thread', 'cyan'); + const expected = color(times, 'green'); + const received = color(callsCount, 'red'); + + return { + pass: callsCount === times, + message: `Expected ${name}${ + this._negation ? ' NOT' : '' + } to be called ${expected} times on ${threadName}, but was called ${received} times`, + }; + }; + + private _toBeCalledJSMatcher: MatcherFunction = ( + currentValue: TestValue, + times = 1 + ) => { + Matchers._assertValueIsCallTracker(currentValue); + const callsCount = currentValue.onJS; + const name = color(currentValue.name, 'green'); + const threadName = color('JS thread', 'cyan'); + const expected = color(times, 'green'); + const received = color(callsCount, 'red'); + + return { + pass: callsCount === times, + message: `Expected ${name}${ + this._negation ? ' NOT' : '' + } to be called ${expected} times on ${threadName}, but was called ${received} times`, + }; + }; + + private decorateMatcher(matcher: MatcherFunction) { + return (expectedValue: TestValue, ...args: Array) => { + const { pass, message } = matcher( + this._currentValue, + expectedValue, + ...args ); - } + if ((!pass && !this._negation) || (pass && this._negation)) { + this._testCase.errors.push(message); + } + }; } - public toBeCalledJS(times = 1) { - this.assertValueIsCallTracker(this.currentValue); - if (this.currentValue.onJS !== times) { - const name = color(this.currentValue.name, 'green'); - const threadName = color('UI thread', 'cyan'); - const expected = color(times, 'green'); - const received = color(this.currentValue.onUI, 'red'); - this.testCase.errors.push( - `Expected ${name} to be called ${expected} times on ${threadName}, but was called ${received} times` - ); - } + public toBe = this.decorateMatcher(this._toBeMatcher); + public toBeCalled = this.decorateMatcher(this._toBeCalledMatcher); + public toBeCalledUI = this.decorateMatcher(this._toBeCalledUIMatcher); + public toBeCalledJS = this.decorateMatcher(this._toBeCalledJSMatcher); + + get not() { + this._negation = true; + return this; } - public toMatchSnapshot(expectedSnapshots: Array>) { - const capturedSnapshots = this.currentValue as Array< + public toMatchSnapshots(expectedSnapshots: Array>) { + const capturedSnapshots = this._currentValue as Array< Record >; if (capturedSnapshots.length !== expectedSnapshots.length) { @@ -79,7 +144,7 @@ export class Matchers { expectedSnapshots.length, capturedSnapshots.length ); - this.testCase.errors.push(errorMessage); + this._testCase.errors.push(errorMessage); } let errorString = ''; expectedSnapshots.forEach( @@ -97,7 +162,7 @@ export class Matchers { } ); if (errorString !== '') { - this.testCase.errors.push('Snapshot mismatch: \n' + errorString); + this._testCase.errors.push('Snapshot mismatch: \n' + errorString); } } @@ -109,7 +174,7 @@ export class Matchers { Updates applied through `_updateProps` are not synchronously applied to the native side. Instead, they are batched and applied at the end of each frame. Therefore, it is not allowed to take a native snapshot immediately after the `_updateProps` call. To address this issue, we need to wait for the next frame before capturing the native snapshot. That's why native snapshots are one frame behind JS snapshots. To account for this delay, one additional native snapshot is taken during the execution of the `getNativeSnapshots` function. */ let errorString = ''; - const jsUpdates = this.currentValue as Array; + const jsUpdates = this._currentValue as Array; for (let i = 0; i < jsUpdates.length; i++) { errorString += this.compareJsAndNativeSnapshot( jsUpdates, @@ -123,7 +188,7 @@ export class Matchers { } snapshots\n`; } if (errorString !== '') { - this.testCase.errors.push('Native snapshot mismatch: \n' + errorString); + this._testCase.errors.push('Native snapshot mismatch: \n' + errorString); } } diff --git a/app/src/examples/RuntimeTests/tests/Animations.test.tsx b/app/src/examples/RuntimeTests/tests/Animations.test.tsx index d408019d826b..8087c990f3fe 100644 --- a/app/src/examples/RuntimeTests/tests/Animations.test.tsx +++ b/app/src/examples/RuntimeTests/tests/Animations.test.tsx @@ -148,6 +148,20 @@ describe('Tests of animations', () => { expect(await component.getAnimatedStyle('width')).toBe('123'); }); + test('withTiming - not - expect error', async () => { + await render(); + const component = getTestComponent('AnimatedComponent'); + await wait(600); + expect(await component.getAnimatedStyle('width')).not.toBe('100'); + }); + + test('withTiming - with not', async () => { + await render(); + const component = getTestComponent('AnimatedComponent'); + await wait(600); + expect(await component.getAnimatedStyle('width')).not.toBe('123'); + }); + test('withTiming - expect pass', async () => { await render(); const component = getTestComponent('AnimatedComponent'); @@ -200,7 +214,9 @@ describe('Tests of animations', () => { const updatesContainer = await recordAnimationUpdates(); await render(); await wait(1000); - expect(updatesContainer.getUpdates()).toMatchSnapshot(Snapshots.animation3); + expect(updatesContainer.getUpdates()).toMatchSnapshots( + Snapshots.animation3 + ); expect(updatesContainer.getUpdates()).toMatchNativeSnapshots( await updatesContainer.getNativeSnapshots() ); @@ -211,7 +227,7 @@ describe('Tests of animations', () => { const updatesContainer = await recordAnimationUpdates(); await render(); await wait(600); - expect(updatesContainer.getUpdates()).toMatchSnapshot( + expect(updatesContainer.getUpdates()).toMatchSnapshots( Snapshots.layoutAnimation ); });