Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Rewrite Testing with Jest page #6503

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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;

//
Loading