Skip to content

Commit

Permalink
docs: Rewrite Testing with Jest page (#6503)
Browse files Browse the repository at this point in the history
To be up to date we've rewritten [Testing with
Jest](https://docs.swmansion.com/react-native-reanimated/docs/guides/testing/),
mostly stylistic changes were made due to not updating Jest integration
for a long time.



https://github.com/user-attachments/assets/f29ca612-375b-4fc8-920a-2f900d5a2e2b
  • Loading branch information
patrycjakalinska authored Sep 20, 2024
1 parent b857008 commit d0c9d7a
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 42 deletions.
84 changes: 42 additions & 42 deletions packages/docs-reanimated/docs/guides/testing-with-jest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,43 @@ id: testing
sidebar_label: 'Testing with Jest'
---

import TestSrc from '!!raw-loader!@site/src/examples/TestExample.tsx';

# Testing with Jest

import DocsCompatibilityInfo from '../_shared/_docs_compatibility_info.mdx';
Reanimated provides testing API, based on Jest. It allows user to mock web-based animations.

<DocsCompatibilityInfo />
## Reference

Reanimated test mocks use web implementation of Reanimated2. Before you begin using Reanimated mocks you need some setup actions.
```js
test('reference', () => {
// some styles

## Setup
const { getByTestId } = render(<AnimatedComponent />);
const view = getByTestId('view');
const button = getByTestId('button');

// highlight-next-line
expect(view).toHaveAnimatedStyle(style);

First, make sure that your tests run with Node version 16 or newer.
fireEvent.press(button);
jest.advanceTimersByTime(250); // if whole animation duration is a 500ms

style.width = 50; // value of component width after 250ms of animation
// highlight-next-line
expect(view).toHaveAnimatedStyle(style);
});
```

## Setup

Add the following line to your `jest-setup.js` file:

```js
require('react-native-reanimated').setUpTests();
```

`setUpTests()` can take optional config argument. Default config is `{ fps: 60 }`, setting framerate to 60fps.
- `setUpTests()` can take optional config argument. Default config is `{ fps: 60 }`.

To be sure, check if your `jest.config.js` file contains:

Expand All @@ -38,28 +56,26 @@ If you use Jest in a version **older than 28**, you should set `setupFiles` prop

:::

If you have custom babel configuration for testing, make sure that Reanimated's babel plugin is enabled in that environment.

## API

#### Style checker
### Style checker

#### `expect(component).toHaveAnimatedStyle(expectedStyle)`

- Checking equality of selected styles with current component styles
Checking equality of selected styles with current component styles.

#### `expect(component).toHaveAnimatedStyle(expectedStyle)`
- `component` - tested component.
- `expectedStyle` - contains expected styles of testing component, for example `{ width: 100 }`.

`component` - tested component
`expectedStyle` - contains expected styles of testing component, for example `{ width: 100 }`
#### `expect(component).toHaveAnimatedStyle(expectedStyle, {exact: true})`

- Checking equality of all current component styles with expected styles
Checking equality of all current component styles with expected styles.

#### `expect(component).toHaveAnimatedStyle(expectedStyle, {exact: true})`
#### `getDefaultStyle(component)`

- You can get all styles of tested component by using `getDefaultStyle`
#### `getDefaultStyle(component)`
`component` - tested component
Gets all styles of tested component.

#### Timers
### Timers

You can use Jest's fake timers to control animation progress.
Check [the full guide about mocking timers on Jest documentation website](https://jestjs.io/docs/timer-mocks).
Expand All @@ -81,33 +97,17 @@ jest.advanceTimersByTime(250);

## Example

The below code shows an example of test that runs a 250ms of animation and verifies the component style after that point in time.

```js
// Setup fake timers – this can be done before the tests are run
jest.useFakeTimers();
<CollapsibleCode src={TestSrc} showLines={[54, 70]} />

test('stop in the middle of animation', () => {
const style = { width: 0 };

const { getByTestId } = render(<AnimatedComponent />);
const view = getByTestId('view');
const button = getByTestId('button');
More examples from `react-native-reanimated` repository:

expect(view.props.style.width).toBe(0);
expect(view).toHaveAnimatedStyle(style);

fireEvent.press(button);
jest.advanceTimersByTime(250); // if whole animation duration is a 500ms
style.width = 50; // value of component width after 250ms of animation
expect(view).toHaveAnimatedStyle(style);
});
```
- [SharedValue.test.tsx](https://github.com/software-mansion/react-native-reanimated/tree/main/packages/react-native-reanimated/__tests__/Animation.test.tsx)
- [Animation.test.tsx](https://github.com/software-mansion/react-native-reanimated/blob/main/packages/react-native-reanimated/__tests__/SharedValue.test.tsx)

Check links below for full examples of tests from Reanimated repo
## Remarks

- [SharedValue.test.tsx](https://github.com/software-mansion/react-native-reanimated/tree/main/__tests__/SharedValue.test.tsx)
- [Animation.test.tsx](https://github.com/software-mansion/react-native-reanimated/tree/main/__tests__/Animation.test.tsx)
- Tests must run with Node 16 or newer.
- If you have custom babel configuration for testing, make sure that Reanimated's babel plugin is enabled in that environment.

## Recommended testing library

Expand Down
84 changes: 84 additions & 0 deletions packages/docs-reanimated/src/examples/TestExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react';
import { View, Button } from 'react-native';
import Animated, {
useAnimatedStyle,
withTiming,
useSharedValue,
SharedValue,
} from 'react-native-reanimated';

interface Props {
sharedValue: SharedValue<number>;
}

const AnimatedSharedValueComponent = (props: Props) => {
const widthSV = props.sharedValue;

const style = useAnimatedStyle(() => {
return {
width: withTiming(widthSV.value, { duration: 500 }),
};
});

return (
<View style={{ flex: 1, flexDirection: 'column' }}>
<Animated.View
testID="view"
style={[
{ width: 0, height: 80, backgroundColor: 'black', margin: 30 },
style,
]}
/>
<Button
testID="button"
title="toggle"
onPress={() => {
widthSV.value = 100;
}}
/>
</View>
);
};

const AnimatedComponent = () => {
return <AnimatedSharedValueComponent sharedValue={useSharedValue(0)} />;
};

const getDefaultStyle = () => ({
width: 0,
height: 80,
backgroundColor: 'black',
margin: 30,
});

describe('Tests of animations', () => {
test('withTiming animation', () => {
const style = getDefaultStyle();

const { getByTestId } = render(<AnimatedComponent />);
const view = getByTestId('view');
const button = getByTestId('button');

expect(view.props.style.width).toBe(0);
expect(view).toHaveAnimatedStyle(style);

fireEvent.press(button);
jest.advanceTimersByTime(600);

style.width = 100;
expect(view).toHaveAnimatedStyle(style);
});
});

// The 'declare const' section is used because the example workspace doesn't require Jest or Jest types installed.
// This prevents TypeScript from throwing errors about 'expect', 'test', and other Jest globals.
// Since we don't want to install '@types/jest', we declare these functions as 'any'.

declare const test: any;
declare const expect: any;
declare const describe: any;
declare const fireEvent: any;
declare const render: any;
declare const jest: any;

//

0 comments on commit d0c9d7a

Please sign in to comment.