Skip to content

Commit

Permalink
Merge branch 'main' into uncaught-rejection-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitri-gb authored Nov 3, 2021
2 parents ff43936 + 95f4969 commit 589c9dc
Show file tree
Hide file tree
Showing 42 changed files with 409 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
steps:
- checkout
- node/install:
lts: true
node-version: '14'
install-npm: false
- node/install-packages: *install
- run:
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

### Features

- `[jest-core]` Add support for `testResultsProcessor` written in ESM ([#12006](https://github.com/facebook/jest/pull/12006))
- `[jest-diff, pretty-format]` Add `compareKeys` option for custom sorting of object keys ([#11992](https://github.com/facebook/jest/pull/11992))

### Fixes

- `[expect]` Allow again `expect.Matchers` generic with single value ([#11986](https://github.com/facebook/jest/pull/11986))
- `[jest-circus, jest-jasmine2]` Avoid false concurrent test failures due to unhandled promise rejections ([#11987](https://github.com/facebook/jest/pull/11987))
- `[jest-core]` Incorrect detection of open ZLIB handles ([#12022](https://github.com/facebook/jest/pull/12022))
- `[jest-environment-jsdom]` Add `@types/jsdom` dependency ([#11999](https://github.com/facebook/jest/pull/11999))
- `[jest-transform]` Improve error and warning messages ([#11998](https://github.com/facebook/jest/pull/11998))

### Chore & Maintenance

Expand Down
4 changes: 2 additions & 2 deletions docs/CodeTransformation.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ If you override the `transform` configuration option `babel-jest` will no longer

## Writing custom transformers

You can write you own transformer. The API of a transformer is as follows:
You can write your own transformer. The API of a transformer is as follows:

```ts
interface SyncTransformer<OptionType = unknown> {
Expand Down Expand Up @@ -124,7 +124,7 @@ type TransformedSource =
// RawSourceMap comes from [`source-map`](https://github.com/mozilla/source-map/blob/0.6.1/source-map.d.ts#L6-L12)
```

As can be seen, only `process` is mandatory to implement, although we highly recommend implementing `getCacheKey` as well, so we don't waste resources transpiling the same source file when we can read its previous result from disk. You can use [`@jest/create-cache-key-function`](https://www.npmjs.com/package/@jest/create-cache-key-function) to help implement it.
As can be seen, only `process` or `processAsync` is mandatory to implement, although we highly recommend implementing `getCacheKey` as well, so we don't waste resources transpiling the same source file when we can read its previous result from disk. You can use [`@jest/create-cache-key-function`](https://www.npmjs.com/package/@jest/create-cache-key-function) to help implement it.

Note that [ECMAScript module](ECMAScriptModules.md) support is indicated by the passed in `supports*` options. Specifically `supportsDynamicImport: true` means the transformer can return `import()` expressions, which is supported by both ESM and CJS. If `supportsStaticESM: true` it means top level `import` statements are supported and the code will be interpreted as ESM and not CJS. See [Node's docs](https://nodejs.org/api/esm.html#esm_differences_between_es_modules_and_commonjs) for details on the differences.

Expand Down
2 changes: 1 addition & 1 deletion docs/JestObjectAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ test('plays audio', () => {

### `jest.clearAllMocks()`

Clears the `mock.calls` and `mock.instances` properties of all mocks. Equivalent to calling [`.mockClear()`](MockFunctionAPI.md#mockfnmockclear) on every mocked function.
Clears the `mock.calls`, `mock.instances` and `mock.results` properties of all mocks. Equivalent to calling [`.mockClear()`](MockFunctionAPI.md#mockfnmockclear) on every mocked function.

Returns the `jest` object for chaining.

Expand Down
10 changes: 2 additions & 8 deletions docs/MockFunctionAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,16 @@ mockFn.mock.instances[1] === b; // true

### `mockFn.mockClear()`

Resets all information stored in the [`mockFn.mock.calls`](#mockfnmockcalls) and [`mockFn.mock.instances`](#mockfnmockinstances) arrays.
Resets all information stored in the [`mockFn.mock.calls`](#mockfnmockcalls), [`mockFn.mock.instances`](#mockfnmockinstances) and [`mockFn.mock.results`](#mockfnmockresults) arrays. Often this is useful when you want to clean up a mocks usage data between two assertions.

Often this is useful when you want to clean up a mocks usage data between two assertions.

Beware that `mockClear` will replace `mockFn.mock`, not just [`mockFn.mock.calls`](#mockfnmockcalls) and [`mockFn.mock.instances`](#mockfnmockinstances). You should, therefore, avoid assigning `mockFn.mock` to other variables, temporary or not, to make sure you don't access stale data.

The [`clearMocks`](configuration#clearmocks-boolean) configuration option is available to clear mocks automatically between tests.
Beware that `mockClear` will replace `mockFn.mock`, not just these three properties! You should, therefore, avoid assigning `mockFn.mock` to other variables, temporary or not, to make sure you don't access stale data. The [`clearMocks`](configuration#clearmocks-boolean) configuration option is available to clear mocks automatically between tests.

### `mockFn.mockReset()`

Does everything that [`mockFn.mockClear()`](#mockfnmockclear) does, and also removes any mocked return values or implementations.

This is useful when you want to completely reset a _mock_ back to its initial state. (Note that resetting a _spy_ will result in a function with no return value).

Beware that `mockReset` will replace `mockFn.mock`, not just [`mockFn.mock.calls`](#mockfnmockcalls) and [`mockFn.mock.instances`](#mockfnmockinstances). You should, therefore, avoid assigning `mockFn.mock` to other variables, temporary or not, to make sure you don't access stale data.

### `mockFn.mockRestore()`

Does everything that [`mockFn.mockReset()`](#mockfnmockreset) does, and also restores the original (non-mocked) implementation.
Expand Down
18 changes: 17 additions & 1 deletion e2e/__tests__/testResultsProcessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
*/

import * as path from 'path';
import {onNodeVersions} from '@jest/test-utils';
import {json as runWithJson} from '../runJest';

test('testNamePattern', () => {
test('testResultsProcessor', () => {
const processorPath = path.resolve(
__dirname,
'../test-results-processor/processor.js',
Expand All @@ -19,3 +20,18 @@ test('testNamePattern', () => {
]);
expect(json.processed).toBe(true);
});

// The versions where vm.Module exists and commonjs with "exports" is not broken
onNodeVersions('>=12.16.0', () => {
test('testResultsProcessor written in ESM', () => {
const processorPath = path.resolve(
__dirname,
'../test-results-processor/processor.mjs',
);
const {json} = runWithJson('test-results-processor', [
'--json',
`--testResultsProcessor=${processorPath}`,
]);
expect(json.processed).toBe(true);
});
});
11 changes: 11 additions & 0 deletions e2e/test-results-processor/processor.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* 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.
*/

export default function (results) {
results.processed = true;
return results;
}
2 changes: 1 addition & 1 deletion packages/jest-circus/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const TEST_TIMEOUT_SYMBOL = Symbol.for(
) as unknown as 'TEST_TIMEOUT_SYMBOL';

declare global {
module NodeJS {
namespace NodeJS {
interface Global {
STATE_SYM_SYMBOL: Circus.State;
RETRY_TIMES_SYMBOL: string;
Expand Down
15 changes: 15 additions & 0 deletions packages/jest-core/src/__tests__/collectHandles.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import {promises as dns} from 'dns';
import http from 'http';
import {PerformanceObserver} from 'perf_hooks';
import zlib from 'zlib';
import collectHandles from '../collectHandles';

describe('collectHandles', () => {
Expand Down Expand Up @@ -52,6 +53,20 @@ describe('collectHandles', () => {
);
});

it('should not collect the ZLIB open handle', async () => {
const handleCollector = collectHandles();

const decompressed = zlib.inflateRawSync(
Buffer.from('cb2a2d2e5128492d2ec9cc4b0700', 'hex'),
);

const openHandles = await handleCollector();

expect(openHandles).not.toContainEqual(
expect.objectContaining({message: 'ZLIB'}),
);
});

it('should collect handles opened in test functions with `done` callbacks', done => {
const handleCollector = collectHandles();
const server = http.createServer((_, response) => response.end('ok'));
Expand Down
3 changes: 2 additions & 1 deletion packages/jest-core/src/collectHandles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export default function collectHandles(): HandleCollectionResult {
type === 'ELDHISTOGRAM' ||
type === 'PerformanceObserver' ||
type === 'RANDOMBYTESREQUEST' ||
type === 'DNSCHANNEL'
type === 'DNSCHANNEL' ||
type === 'ZLIB'
) {
return;
}
Expand Down
6 changes: 5 additions & 1 deletion packages/jest-core/src/runJest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {CustomConsole} from '@jest/console';
import {
AggregatedResult,
Test,
TestResultsProcessor,
formatTestResults,
makeEmptyAggregatedTestResult,
} from '@jest/test-result';
Expand Down Expand Up @@ -96,7 +97,10 @@ const processResults = async (
}

if (testResultsProcessor) {
runResults = require(testResultsProcessor)(runResults);
const processor = await requireOrImportModule<TestResultsProcessor>(
testResultsProcessor,
);
runResults = processor(runResults);
}
if (isJSON) {
if (outputFile) {
Expand Down
57 changes: 57 additions & 0 deletions packages/jest-diff/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ For other applications, you can provide an options object as a third argument:
| `commonColor` | `chalk.dim` |
| `commonIndicator` | `' '` |
| `commonLineTrailingSpaceColor` | `string => string` |
| `compareKeys` | `undefined` |
| `contextLines` | `5` |
| `emptyFirstOrLastLinePlaceholder` | `''` |
| `expand` | `true` |
Expand Down Expand Up @@ -612,3 +613,59 @@ If a content line is empty, then the corresponding comparison line is automatica
| `aIndicator` | `'-·'` | `'-'` |
| `bIndicator` | `'+·'` | `'+'` |
| `commonIndicator` | `' ·'` | `''` |

### Example of option for sorting object keys

When two objects are compared their keys are printed in alphabetical order by default. If this was not the original order of the keys the diff becomes harder to read as the keys are not in their original position.

Use `compareKeys` to pass a function which will be used when sorting the object keys.

```js
const a = {c: 'c', b: 'b1', a: 'a'};
const b = {c: 'c', b: 'b2', a: 'a'};

const options = {
// The keys will be in their original order
compareKeys: () => 0,
};

const difference = diff(a, b, options);
```

```diff
- Expected
+ Received

Object {
"c": "c",
- "b": "b1",
+ "b": "b2",
"a": "a",
}
```

Depending on the implementation of `compareKeys` any sort order can be used.

```js
const a = {c: 'c', b: 'b1', a: 'a'};
const b = {c: 'c', b: 'b2', a: 'a'};

const options = {
// The keys will be in reverse order
compareKeys: (a, b) => (a > b ? -1 : 1),
};

const difference = diff(a, b, options);
```

```diff
- Expected
+ Received

Object {
"a": "a",
- "b": "b1",
+ "b": "b2",
"c": "c",
}
```
39 changes: 39 additions & 0 deletions packages/jest-diff/src/__tests__/diff.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1120,4 +1120,43 @@ describe('options', () => {
expect(diffStringsUnified(aEmpty, bEmpty, options)).toBe(expected);
});
});

describe('compare keys', () => {
const a = {a: {d: 1, e: 1, f: 1}, b: 1, c: 1};
const b = {a: {d: 1, e: 2, f: 1}, b: 1, c: 1};

test('keeps the object keys in their original order', () => {
const compareKeys = () => 0;
const expected = [
' Object {',
' "a": Object {',
' "d": 1,',
'- "e": 1,',
'+ "e": 2,',
' "f": 1,',
' },',
' "b": 1,',
' "c": 1,',
' }',
].join('\n');
expect(diff(a, b, {...optionsBe, compareKeys})).toBe(expected);
});

test('sorts the object keys in reverse order', () => {
const compareKeys = (a: string, b: string) => (a > b ? -1 : 1);
const expected = [
' Object {',
' "c": 1,',
' "b": 1,',
' "a": Object {',
' "f": 1,',
'- "e": 1,',
'+ "e": 2,',
' "d": 1,',
' },',
' }',
].join('\n');
expect(diff(a, b, {...optionsBe, compareKeys})).toBe(expected);
});
});
});
Loading

0 comments on commit 589c9dc

Please sign in to comment.