Skip to content

Commit

Permalink
Merge branch 'facebook:main' into eli5-video-update
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitryvinn-fb authored Feb 13, 2022
2 parents 5468f74 + faef0b4 commit a501c2c
Show file tree
Hide file tree
Showing 36 changed files with 413 additions and 224 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto
16 changes: 9 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,41 @@

### Features

- `[expect]` [**BREAKING**] Migrate to ESM ([#12344](https://github.com/facebook/jest/pull/12344))
- `[jest-config]` [**BREAKING**] Stop shipping `jest-environment-jsdom` by default ([#12354](https://github.com/facebook/jest/pull/12354))
- `[jest-config]` [**BREAKING**] Stop shipping `jest-jasmine2` by default ([#12355](https://github.com/facebook/jest/pull/12355))
- `[jest-environment-jsdom]` [**BREAKING**] Upgrade jsdom to 19.0.0 ([#12290](https://github.com/facebook/jest/pull/12290))
- `[jest-environment-jsdom]` [**BREAKING**] Add default `browser` condition to `exportConditions` for `jsdom` environment ([#11924](https://github.com/facebook/jest/pull/11924))
- `[jest-environment-jsdom]` [**BREAKING**] Migrate to ESM ([#12340](https://github.com/facebook/jest/pull/12340))
- `[jest-environment-node]` [**BREAKING**] Add default `node` and `node-addon` conditions to `exportConditions` for `node` environment ([#11924](https://github.com/facebook/jest/pull/11924))
- `[jest-environment-node]` [**BREAKING**] Migrate to ESM ([#12340](https://github.com/facebook/jest/pull/12340))
- `[@jest/expect-utils]` New module exporting utils for `expect` ([#12323](https://github.com/facebook/jest/pull/12323))
- `[jest-jasmine2, jest-runtime]` [**BREAKING**] Use `Symbol` to pass `jest.setTimeout` value instead of `jasmine` specific logic ([#12124](https://github.com/facebook/jest/pull/12124))
- `[jest-jasmine2, jest-types]` [**BREAKING**] Move all `jasmine` specific types from `@jest/types` to its own package ([#12125](https://github.com/facebook/jest/pull/12125))
- `[jest-resolver]` [**BREAKING**] Add support for `package.json` `exports` ([11961](https://github.com/facebook/jest/pull/11961))
- `[jest-snapshot]` [**BREAKING**] Migrate to ESM ([#12342](https://github.com/facebook/jest/pull/12342))
- `[jest-worker]` [**BREAKING**] Allow only absolute `workerPath` ([#12343](https://github.com/facebook/jest/pull/12343))

### Fixes

- `[expect]` Move typings of `.not`, `.rejects` and `.resolves` modifiers outside of `Matchers` interface ([#12346](https://github.com/facebook/jest/pull/12346))
- `[expect]` Expose `AsymmetricMatchers` and `RawMatcherFn` interfaces ([#12363](https://github.com/facebook/jest/pull/12363))
- `[jest-environment-jsdom]` Make `jsdom` accessible to extending environments again ([#12232](https://github.com/facebook/jest/pull/12232))
- `[jest-phabricator]` [**BREAKING**] Convert to ESM ([#12341](https://github.com/facebook/jest/pull/12341))
- `[jest-jasmine2, jest-types]` [**BREAKING**] Move all `jasmine` specific types from `@jest/types` to its own package ([#12125](https://github.com/facebook/jest/pull/12125))

### Chore & Maintenance

- `[*]` [**BREAKING**] Drop support for Node v10 and v15 and target first LTS `16.13.0` ([#12220](https://github.com/facebook/jest/pull/12220))
- `[*]` [**BREAKING**] Drop support for `[email protected]`, minimum version is now `4.2` ([#11142](https://github.com/facebook/jest/pull/11142))
- `[*]` Bundle all `.d.ts` files into a single `index.d.ts` per module ([#12345](https://github.com/facebook/jest/pull/12345))
- `[docs, examples]` Update React examples to match with the new React guidelines for code examples ([#12217](https://github.com/facebook/jest/pull/12217))
- `[expect]` [**BREAKING**] Remove support for importing `build/utils` ([#12323](https://github.com/facebook/jest/pull/12323))
- `[expect]` [**BREAKING**] Migrate to ESM ([#12344](https://github.com/facebook/jest/pull/12344))
- `[jest-cli]` Update `yargs` to v17 ([#12357](https://github.com/facebook/jest/pull/12357))
- `[jest-config]` [**BREAKING**] Remove `getTestEnvironment` export ([#12353](https://github.com/facebook/jest/pull/12353))
- `[@jest/core]` Use `index.ts` instead of `jest.ts` as main export ([#12329](https://github.com/facebook/jest/pull/12329))
- `[jest-environment-jsdom]` [**BREAKING**] Migrate to ESM ([#12340](https://github.com/facebook/jest/pull/12340))
- `[jest-environment-node]` [**BREAKING**] Migrate to ESM ([#12340](https://github.com/facebook/jest/pull/12340))
- `[@jest/fake-timers]` Update `@sinonjs/fake_timers` to v9 ([#12357](https://github.com/facebook/jest/pull/12357))
- `[jest-jasmine2, jest-runtime]` [**BREAKING**] Use `Symbol` to pass `jest.setTimeout` value instead of `jasmine` specific logic ([#12124](https://github.com/facebook/jest/pull/12124))
- `[jest-phabricator]` [**BREAKING**] Migrate to ESM ([#12341](https://github.com/facebook/jest/pull/12341))
- `[jest-resolve]` [**BREAKING**] Make `requireResolveFunction` argument mandatory ([#12353](https://github.com/facebook/jest/pull/12353))
- `[jest-runner]` [**BREAKING**] Remove some type exports from `@jest/test-result` ([#12353](https://github.com/facebook/jest/pull/12353))
- `[jest-snapshot]` [**BREAKING**] Migrate to ESM ([#12342](https://github.com/facebook/jest/pull/12342))
- `[jest-transform]` Update `write-file-atomic` to v4 ([#12357](https://github.com/facebook/jest/pull/12357))
- `[jest]` Use `index.ts` instead of `jest.ts` as main export ([#12329](https://github.com/facebook/jest/pull/12329))

Expand Down
1 change: 0 additions & 1 deletion docs/SnapshotTesting.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ A typical snapshot test case renders a UI component, takes a snapshot, then comp
A similar approach can be taken when it comes to testing your React components. Instead of rendering the graphical UI, which would require building the entire app, you can use a test renderer to quickly generate a serializable value for your React tree. Consider this [example test](https://github.com/facebook/jest/blob/main/examples/snapshot/__tests__/link.test.js) for a [Link component](https://github.com/facebook/jest/blob/main/examples/snapshot/Link.js):

```tsx
import React from 'react';
import renderer from 'react-test-renderer';
import Link from '../Link';

Expand Down
61 changes: 34 additions & 27 deletions docs/TutorialReact.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ Your `package.json` should look something like this (where `<current-version>` i

```js title="babel.config.js"
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
```

Expand All @@ -59,14 +62,14 @@ module.exports = {
Let's create a [snapshot test](SnapshotTesting.md) for a Link component that renders hyperlinks:

```tsx title="Link.js"
import React, {useState} from 'react';
import {useState} from 'react';

const STATUS = {
HOVERED: 'hovered',
NORMAL: 'normal',
};

const Link = ({page, children}) => {
export default function Link({page, children}) {
const [status, setStatus] = useState(STATUS.NORMAL);

const onMouseEnter = () => {
Expand All @@ -87,35 +90,36 @@ const Link = ({page, children}) => {
{children}
</a>
);
};

export default Link;
}
```

> Note: Examples are using Function components, but Class components can be tested in the same way. See [React: Function and Class Components](https://reactjs.org/docs/components-and-props.html#function-and-class-components). **Reminders** that with Class components, we expect Jest to be used to test props and not methods directly.
Now let's use React's test renderer and Jest's snapshot feature to interact with the component and capture the rendered output and create a snapshot file:

```tsx title="Link.react.test.js"
import React from 'react';
import renderer from 'react-test-renderer';
import Link from '../Link.react';
import renderer from 'react-test-renderer';

test('Link changes the class when hovered', () => {
it('changes the class when hovered', () => {
const component = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();

// manually trigger the callback
tree.props.onMouseEnter();
renderer.act(() => {
tree.props.onMouseEnter();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();

// manually trigger the callback
tree.props.onMouseLeave();
renderer.act(() => {
tree.props.onMouseLeave();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
Expand All @@ -125,32 +129,35 @@ test('Link changes the class when hovered', () => {
When you run `yarn test` or `jest`, this will produce an output file like this:

```javascript title="__tests__/__snapshots__/Link.react.test.js.snap"
exports[`Link changes the class when hovered 1`] = `
exports[`changes the class when hovered 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}>
onMouseLeave={[Function]}
>
Facebook
</a>
`;

exports[`Link changes the class when hovered 2`] = `
exports[`changes the class when hovered 2`] = `
<a
className="hovered"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}>
onMouseLeave={[Function]}
>
Facebook
</a>
`;

exports[`Link changes the class when hovered 3`] = `
exports[`changes the class when hovered 3`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}>
onMouseLeave={[Function]}
>
Facebook
</a>
`;
Expand All @@ -160,7 +167,7 @@ The next time you run the tests, the rendered output will be compared to the pre

The code for this example is available at [examples/snapshot](https://github.com/facebook/jest/tree/main/examples/snapshot).

#### Snapshot Testing with Mocks, Enzyme and React 16
#### Snapshot Testing with Mocks, Enzyme and React 16+

There's a caveat around snapshot testing when using Enzyme and React 16+. If you mock out a module using the following style:

Expand Down Expand Up @@ -205,9 +212,9 @@ You have to run `yarn add --dev @testing-library/react` to use react-testing-lib
Let's implement a checkbox which swaps between two labels:
```tsx title="CheckboxWithLabel.js"
import React, {useState} from 'react';
import {useState} from 'react';
const CheckboxWithLabel = ({labelOn, labelOff}) => {
export default function CheckboxWithLabel({labelOn, labelOff}) {
const [isChecked, setIsChecked] = useState(false);
const onChange = () => {
Expand All @@ -220,13 +227,10 @@ const CheckboxWithLabel = ({labelOn, labelOff}) => {
{isChecked ? labelOn : labelOff}
</label>
);
};
export default CheckboxWithLabel;
}
```
```tsx title="__tests__/CheckboxWithLabel-test.js"
import React from 'react';
import {cleanup, fireEvent, render} from '@testing-library/react';
import CheckboxWithLabel from '../CheckboxWithLabel';
Expand Down Expand Up @@ -256,11 +260,14 @@ You have to run `yarn add --dev enzyme` to use Enzyme. If you are using a React
Let's rewrite the test from above using Enzyme instead of react-testing-library. We use Enzyme's [shallow renderer](http://airbnb.io/enzyme/docs/api/shallow.html) in this example.
```tsx title="__tests__/CheckboxWithLabel-test.js"
import React from 'react';
import {shallow} from 'enzyme';
import Enzyme, {shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
import CheckboxWithLabel from '../CheckboxWithLabel';
test('CheckboxWithLabel changes the text after click', () => {
it('CheckboxWithLabel changes the text after click', () => {
// Render a checkbox with label in the document
const checkbox = shallow(<CheckboxWithLabel labelOn="On" labelOff="Off" />);
Expand Down
2 changes: 1 addition & 1 deletion e2e/__tests__/failures.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ test('errors after test has completed', () => {
const {stderr} = runJest(dir, ['errorAfterTestComplete.test.js']);

expect(stderr).toMatch(
/Error: Caught error after test environment was torn down/,
/Error(WithStack)?: Caught error after test environment was torn down/,
);
expect(stderr).toMatch(/Failed: "fail async"/);
});
6 changes: 4 additions & 2 deletions examples/enzyme/.babelrc.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.

module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['@babel/plugin-proposal-class-properties']
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
40 changes: 21 additions & 19 deletions examples/enzyme/CheckboxWithLabel.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
// Copyright 2004-present Facebook. All Rights Reserved.

import React from 'react';
import {useState} from 'react';

export default class CheckboxWithLabel extends React.Component {
state = {
isChecked: false,
};
export default function CheckboxWithLabel({
labelRef,
inputRef,
labelOn,
labelOff,
}) {
const [isChecked, setIsChecked] = useState(false);

onChange = () => {
this.setState({isChecked: !this.state.isChecked});
const onChange = () => {
setIsChecked(!isChecked);
};

render() {
return (
<label>
<input
type="checkbox"
checked={this.state.isChecked}
onChange={this.onChange}
/>
{this.state.isChecked ? this.props.labelOn : this.props.labelOff}
</label>
);
}
return (
<label ref={labelRef}>
<input
ref={inputRef}
type="checkbox"
checked={isChecked}
onChange={onChange}
/>
{isChecked ? labelOn : labelOff}
</label>
);
}
1 change: 0 additions & 1 deletion examples/enzyme/__tests__/CheckboxWithLabel-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright 2004-present Facebook. All Rights Reserved.

import React from 'react';
import Enzyme, {shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Expand Down
20 changes: 20 additions & 0 deletions examples/expect-extend/__tests__/ranges.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {expect, test} from '@jest/globals';
import '../toBeWithinRange';

test('is within range', () => expect(100).toBeWithinRange(90, 110));

test('is NOT within range', () => expect(101).not.toBeWithinRange(0, 100));

test('asymmetric ranges', () => {
expect({apples: 6, bananas: 3}).toEqual({
apples: expect.toBeWithinRange(1, 10),
bananas: expect.not.toBeWithinRange(11, 20),
});
});
30 changes: 30 additions & 0 deletions examples/expect-extend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"private": true,
"version": "0.0.0",
"name": "example-expect-extend",
"devDependencies": {
"@babel/core": "*",
"@babel/preset-env": "*",
"@babel/preset-typescript": "*",
"@jest/globals": "workspace:*",
"babel-jest": "workspace:*",
"expect": "workspace:*",
"jest": "workspace:*"
},
"scripts": {
"test": "jest"
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"@babel/preset-typescript"
]
}
}
43 changes: 43 additions & 0 deletions examples/expect-extend/toBeWithinRange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {expect} from '@jest/globals';
import type {RawMatcherFn} from 'expect';

const toBeWithinRange: RawMatcherFn = (
actual: number,
floor: number,
ceiling: number,
) => {
const pass = actual >= floor && actual <= ceiling;
if (pass) {
return {
message: () =>
`expected ${actual} not to be within range ${floor} - ${ceiling}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${actual} to be within range ${floor} - ${ceiling}`,
pass: false,
};
}
};

expect.extend({
toBeWithinRange,
});

declare module 'expect' {
interface AsymmetricMatchers {
toBeWithinRange(a: number, b: number): void;
}
interface Matchers<R> {
toBeWithinRange(a: number, b: number): R;
}
}
Loading

0 comments on commit a501c2c

Please sign in to comment.