Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/common-app/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ module.exports = {
'reanimated/animated-style-non-animated-component': 'error',
'react/jsx-fragments': ['error', 'syntax'],
},
overrides: [
{
files: ['./src/examples/RuntimeTests/tests/**'],
rules: {
'no-template-curly-in-string': 'off',
},
},
],
};
Original file line number Diff line number Diff line change
@@ -1,96 +1,78 @@
import { Component, ReactElement } from 'react';
import type { Component, ReactElement } from 'react';
import { TestRunner } from './TestRunner';
import { TestComponent } from './TestComponent';
import type { TestComponent } from './TestComponent';
import type { SharedValue } from 'react-native-reanimated';
import { TestConfiguration, TestValue, NullableTestValue, DescribeDecorator, TestDecorator } from './types';
import type { TestConfiguration, TestValue, NullableTestValue, BuildFunction } from './types';
import { DescribeDecorator, TestDecorator } from './types';

export { Presets } from './Presets';

const testRunner = new TestRunner();

type DescribeFunction = (name: string, buildSuite: () => void) => void;
export const describe: {
(name: string, buildSuite: () => void): void;
skip: DescribeFunction;
only: DescribeFunction;
} = Object.assign(
(name: string, buildSuite: () => void) => {
testRunner.describe(name, buildSuite, null);
},
{
skip: (name: string, buildSuite: () => void) => {
testRunner.describe(name, buildSuite, DescribeDecorator.SKIP);
},
only: (name: string, buildSuite: () => void) => {
testRunner.describe(name, buildSuite, DescribeDecorator.ONLY);
},
},
);

type DescribeFunction = (name: string, buildSuite: BuildFunction) => void;
type TestFunction = (name: string, buildTest: BuildFunction) => void;
type TestFunctionWithWarning = (name: string, warningMessage: string, buildTest: BuildFunction) => void;
type TestEachFunction = <T>(
examples: Array<T>,
) => (name: string, testCase: (example: T, index?: number) => void) => void;
) => (name: string, testCase: (example: T, index?: number) => void | Promise<void>) => void;
type TestEachFunctionWithWarning = <T>(
examples: Array<T>,
) => (name: string, expectedWarning: string, testCase: (example: T, index?: number) => void) => void;

export const test: {
(name: string, testCase: () => void): void;
each: TestEachFunction;
skip: { (name: string, testCase: () => void): void; each: TestEachFunction };
only: { (name: string, testCase: () => void): void; each: TestEachFunction };
failing: { (name: string, warningMessage: string, testCase: () => void): void; each: TestEachFunctionWithWarning };
warn: { (name: string, warningMessage: string, testCase: () => void): void; each: TestEachFunctionWithWarning };
} = Object.assign(
(name: string, testCase: () => void) => {
testRunner.test(name, testCase, null);
},
{
each: <T>(examples: Array<T>) => {
return testRunner.testEach(examples, null);
},
skip: Object.assign(
(name: string, testCase: () => void) => {
testRunner.test(name, testCase, TestDecorator.SKIP);
},
{
each: <T>(examples: Array<T>) => {
return testRunner.testEach(examples, TestDecorator.SKIP);
},
},
),
only: Object.assign(
(name: string, testCase: () => void) => {
testRunner.test(name, testCase, TestDecorator.ONLY);
},
{
each: <T>(examples: Array<T>) => {
return testRunner.testEach(examples, TestDecorator.ONLY);
},
},
),
failing: Object.assign(
(name: string, expectedWarning: string, testCase: () => void) => {
testRunner.test(name, testCase, TestDecorator.FAILING, expectedWarning);
},
{
each: <T>(examples: Array<T>) => {
return testRunner.testEachErrorMsg(examples, TestDecorator.FAILING);
},
},
),
warn: Object.assign(
(name: string, expectedWarning: string, testCase: () => void) => {
testRunner.test(name, testCase, TestDecorator.WARN, expectedWarning);
},
{
each: <T>(examples: Array<T>) => {
return testRunner.testEachErrorMsg(examples, TestDecorator.WARN);
},
},
),
},
);
) => (name: string, expectedWarning: string, testCase: (example: T, index?: number) => void | Promise<void>) => void;
type DecoratedTestFunction = TestFunction & { each: TestEachFunction };
type DecoratedTestFunctionWithWarning = TestFunctionWithWarning & { each: TestEachFunctionWithWarning };

const describeBasic = (name: string, buildSuite: BuildFunction) => {
testRunner.describe(name, buildSuite, null);
};

export const describe = <DescribeFunction & Record<DescribeDecorator, DescribeFunction>>describeBasic;
describe.skip = (name, buildSuite) => {
testRunner.describe(name, buildSuite, DescribeDecorator.SKIP);
};
describe.only = (name, buildSuite) => {
testRunner.describe(name, buildSuite, DescribeDecorator.ONLY);
};

const testBasic: DecoratedTestFunction = (name: string, testCase: BuildFunction) => {
testRunner.test(name, testCase, null);
};
testBasic.each = <T>(examples: Array<T>) => {
return testRunner.testEach(examples, null);
};
const testSkip: DecoratedTestFunction = (name: string, testCase: BuildFunction) => {
testRunner.test(name, testCase, TestDecorator.SKIP);
};
testSkip.each = <T>(examples: Array<T>) => {
return testRunner.testEach(examples, TestDecorator.SKIP);
};
const testOnly: DecoratedTestFunction = (name: string, testCase: BuildFunction) => {
testRunner.test(name, testCase, TestDecorator.ONLY);
};
testOnly.each = <T>(examples: Array<T>) => {
return testRunner.testEach(examples, TestDecorator.ONLY);
};
const testFailing: DecoratedTestFunctionWithWarning = (name: string, expectedWarning: string, testCase: () => void) => {
testRunner.test(name, testCase, TestDecorator.FAILING, expectedWarning);
};
testFailing.each = <T>(examples: Array<T>) => {
return testRunner.testEachErrorMsg(examples, TestDecorator.FAILING);
};
const testWarn: DecoratedTestFunctionWithWarning = (name: string, expectedWarning: string, testCase: () => void) => {
testRunner.test(name, testCase, TestDecorator.WARN, expectedWarning);
};
testWarn.each = <T>(examples: Array<T>) => {
return testRunner.testEachErrorMsg(examples, TestDecorator.WARN);
};

export const test = <
DecoratedTestFunction &
Record<TestDecorator.SKIP | TestDecorator.ONLY, DecoratedTestFunction> &
Record<TestDecorator.FAILING | TestDecorator.WARN, DecoratedTestFunctionWithWarning>
>testBasic;
test.skip = testSkip;
test.only = testOnly;
test.failing = testFailing;
test.warn = testWarn;

export function beforeAll(job: () => void) {
testRunner.beforeAll(job);
Expand Down Expand Up @@ -120,6 +102,7 @@ export function useTestRef(name: string) {
return testRunner.useTestRef(name);
}

// eslint-disable-next-line @typescript-eslint/unbound-method
Comment thread
Latropos marked this conversation as resolved.
const testRunnerCallTrackerFn = testRunner.callTracker;
export function callTracker(name: string) {
'worklet';
Expand Down Expand Up @@ -158,8 +141,9 @@ export async function wait(delay: number) {
return testRunner.wait(delay);
}

// eslint-disable-next-line @typescript-eslint/unbound-method
Comment thread
Latropos marked this conversation as resolved.
const testRunnerNotifyFn = testRunner.notify;
export async function notify(name: string) {
export function notify(name: string) {
'worklet';
return testRunnerNotifyFn(name);
}
Expand Down Expand Up @@ -209,5 +193,5 @@ export async function recordAnimationUpdates() {
}

export async function stopRecordingAnimationUpdates() {
testRunner.stopRecordingAnimationUpdates();
await testRunner.stopRecordingAnimationUpdates();
Comment thread
Latropos marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { Component, MutableRefObject, ReactElement, useRef } from 'react';
import {
type NullableTestValue,
type LockObject,
type Operation,
type SharedValueSnapshot,
type TestCase,
type TestConfiguration,
type TestSuite,
type TestSummary,
type TestValue,
type TrackerCallCount,
ComparisonMode,
DescribeDecorator,
TestDecorator,
import type { Component, MutableRefObject, ReactElement } from 'react';
import { useRef } from 'react';
import type {
BuildFunction,
NullableTestValue,
LockObject,
Operation,
SharedValueSnapshot,
TestCase,
TestConfiguration,
TestSuite,
TestSummary,
TestValue,
TrackerCallCount,
} from './types';
import { ComparisonMode, DescribeDecorator, TestDecorator } from './types';
import { TestComponent } from './TestComponent';
import { getTrackerCallCount, render, stopRecordingAnimationUpdates, unmockAnimationTimer } from './RuntimeTestsApi';
import { makeMutable, runOnUI, runOnJS, SharedValue } from 'react-native-reanimated';
import type { SharedValue } from 'react-native-reanimated';
import { makeMutable, runOnUI, runOnJS } from 'react-native-reanimated';
import { applyMarkdown, color, formatString, indentNestingLevel } from './stringFormatUtils';
import { createUpdatesContainer } from './UpdatesContainer';
import { Matchers, nullableMatch } from './Matchers';
Expand Down Expand Up @@ -101,7 +102,7 @@ export class TestRunner {
return await this.render(null);
}

public describe(name: string, buildSuite: () => void, decorator: DescribeDecorator | null) {
public describe(name: string, buildSuite: BuildFunction, decorator: DescribeDecorator | null) {
if (decorator === DescribeDecorator.ONLY) {
this._includesOnly = true;
}
Expand All @@ -127,11 +128,12 @@ export class TestRunner {
buildSuite,
testCases: [],
nestingLevel: (this._currentTestSuite?.nestingLevel || 0) + 1,
// eslint-disable-next-line no-unneeded-ternary
Comment thread
Latropos marked this conversation as resolved.
decorator: decorator ? decorator : this._currentTestSuite?.decorator ? this._currentTestSuite?.decorator : null,
});
}

public test(name: string, run: () => void, decorator: TestDecorator | null, warningMessage = '') {
public test(name: string, run: BuildFunction, decorator: TestDecorator | null, warningMessage = '') {
assertTestSuite(this._currentTestSuite);
if (decorator === TestDecorator.ONLY) {
this._includesOnly = true;
Expand All @@ -145,7 +147,7 @@ export class TestRunner {
callsRegistry: {},
errors: [],
decorator,
warningMessage: warningMessage,
warningMessage,
skip: false,
}
: {
Expand All @@ -161,7 +163,7 @@ export class TestRunner {
}

public testEachErrorMsg<T>(examples: Array<T>, decorator: TestDecorator) {
return (name: string, expectedWarning: string, testCase: (example: T) => void) => {
return (name: string, expectedWarning: string, testCase: (example: T) => void | Promise<void>) => {
examples.forEach((example, index) => {
const currentTestCase = async () => {
await testCase(example);
Expand All @@ -175,8 +177,9 @@ export class TestRunner {
});
};
}

public testEach<T>(examples: Array<T>, decorator: TestDecorator | null) {
return (name: string, testCase: (example: T, index?: number) => void) => {
return (name: string, testCase: (example: T, index?: number) => void | Promise<void>) => {
examples.forEach((example, index) => {
const currentTestCase = async () => {
await testCase(example, index);
Expand Down Expand Up @@ -260,7 +263,9 @@ export class TestRunner {
for (const testCase of testSuite.testCases) {
if (testCase.decorator === TestDecorator.ONLY) {
skipTestSuite = false;
} else testCase.skip = testCase.skip || !(testSuite.decorator === DescribeDecorator.ONLY);
} else {
testCase.skip = testCase.skip || !(testSuite.decorator === DescribeDecorator.ONLY);
}
}
}
testSuite.skip = skipTestSuite;
Expand Down Expand Up @@ -323,6 +328,7 @@ export class TestRunner {
console.error = newConsoleFuncJS;
console.warn = newConsoleFuncJS;

// eslint-disable-next-line @typescript-eslint/unbound-method
Comment thread
Latropos marked this conversation as resolved.
const callTrackerCopy = this.callTracker;

runOnUI(() => {
Expand Down Expand Up @@ -500,12 +506,13 @@ export class TestRunner {
return global.mockedAnimationTimestamp;
};

let originalRequestAnimationFrame = global.requestAnimationFrame;
const originalRequestAnimationFrame = global.requestAnimationFrame;
global.originalRequestAnimationFrame = originalRequestAnimationFrame;
(global as any).requestAnimationFrame = (callback: Function) => {
global.requestAnimationFrame = (callback: (time: number) => void) => {
originalRequestAnimationFrame(() => {
callback(global._getAnimationTimestamp());
});
return 0;
};

global.originalFlushAnimationFrame = global.__flushAnimationFrame;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Dispatch, MutableRefObject, ReactNode, SetStateAction } from 'react';
import { AnimatedStyle, StyleProps } from 'react-native-reanimated';
import type { Component, Dispatch, MutableRefObject, ReactNode, SetStateAction } from 'react';
import type { AnimatedStyle, StyleProps } from 'react-native-reanimated';

export type CallTracker = {
UICallsCount: number;
Expand All @@ -25,22 +25,22 @@ export type SharedValueSnapshot = {
export type ComponentRef = MutableRefObject<(Component & { props: { style: Record<string, unknown> } }) | null>;

export enum DescribeDecorator {
ONLY = 'ONLY',
SKIP = 'SKIP',
NONE = 'NONE',
ONLY = 'only',
SKIP = 'skip',
Comment thread
Latropos marked this conversation as resolved.
}

export enum TestDecorator {
ONLY = 'ONLY',
SKIP = 'SKIP',
FAILING = 'FAILING',
WARN = 'WARN',
NONE = 'NONE',
ONLY = 'only',
SKIP = 'skip',
FAILING = 'failing',
WARN = 'warn',
}

export type BuildFunction = () => void | Promise<void>;

export type TestCase = {
name: string;
run: () => void | Promise<void>;
run: BuildFunction;
componentsRefs: Record<string, ComponentRef>;
callsRegistry: Record<string, CallTracker>;
errors: string[];
Expand All @@ -55,7 +55,7 @@ export type TestCase = {

export type TestSuite = {
name: string;
buildSuite: () => void;
buildSuite: BuildFunction;
testCases: TestCase[];
nestingLevel: number;
beforeAll?: () => void | Promise<void>;
Expand Down Expand Up @@ -104,6 +104,7 @@ export type TestConfiguration = {
render: Dispatch<SetStateAction<ReactNode | null>>;
};

/* eslint-disable no-var */
Comment thread
Latropos marked this conversation as resolved.
declare global {
var mockedAnimationTimestamp: number | undefined;
var originalRequestAnimationFrame: ((callback: (timestamp: number) => void) => void) | undefined;
Expand All @@ -123,6 +124,7 @@ declare global {
var _obtainPropFabric: (shadowNodeWrapper: unknown, propName: string) => string;
var __flushAnimationFrame: (frameTimestamp: number) => void;
}
/* eslint-enable no-var */

export type TestSummary = {
passed: number;
Expand Down
Loading