Skip to content

Commit

Permalink
Merge pull request #1 from facebook/master
Browse files Browse the repository at this point in the history
Merging changes from Origin
  • Loading branch information
mute authored Mar 30, 2017
2 parents e79ad74 + a0864db commit ec3a6a0
Show file tree
Hide file tree
Showing 76 changed files with 3,885 additions and 2,857 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"extends": "./packages/eslint-config-fb-strict/index.js",
"parser": "babel-eslint",
"rules": {
"no-multiple-empty-lines": 1
"no-multiple-empty-lines": 1,
"flowtype/require-valid-file-annotation": 2
},
"plugins": [
"markdown"
Expand Down
2 changes: 2 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ If enabled, the module registry for every test file will be reset before running
### `resolver` [string]
Default: `undefined`

##### available in Jest **20.0.0+**

This option allows the use of a custom resolver. This resolver must be a node module that exports a function expecting a string as the first argument for the path to resolve and an object with the following structure as the second argument:

```
Expand Down
54 changes: 53 additions & 1 deletion docs/ExpectAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,58 @@ test('the best flavor is not coconut', () => {
});
```

### `.resolves`

##### available in Jest **20.0.0+**

If your code uses Promises, use the `.resolves` keyword, and Jest will wait for the Promise to resolve and then run an assertion on the resulting value.

For example, this code tests that the Promise returned by `fetchData()` resolves and that the resulting value is peanut butter:

```js
test('fetchData() resolves and is peanut butter', () => {
// make sure to add a return statement
return expect(fetchData()).resolves.toBe('peanut butter');
});
```

Alternatively, you can use `async/await` in combination with `.resolves`:

```js
test('fetchData() resolves and is peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
await expect(fetchData()).resolves.not.toBe('coconut');
});
```

### `.rejects`

##### available in Jest **20.0.0+**

If your code uses Promises, use the `.rejects` keyword, and Jest will wait for that Promise to reject and then run an assertion on the resulting value.

For example, this code tests that the Promise returned by `fetchData()` rejects and that the resulting value is an error:

```js
test('fetchData() rejects to be error', () => {
// make sure to add a return statement
return expect(fetchData()).rejects.toEqual({
error: 'User not found',
});
});
```

Alternatively, you can use `async/await` in combination with `.rejects`:

```js
test('fetchData() rejects to be error', async () => {
await expect(fetchData()).rejects.toEqual({
error: 'User not found',
});
await expect(fetchData()).rejects.not.toBe('Mark');
});
```

### `.toBe(value)`

`toBe` just checks that a value is what you expect. It uses `===` to check
Expand Down Expand Up @@ -566,7 +618,7 @@ describe('my beverage', () => {

### `.toEqual(value)`

Use `.toEqual` when you want to check that two objects have the same value. This matcher recursively checks the equality of all fields, rather than checking for object identity. For example, `toEqual` and `toBe` behave differently in this test suite, so all the tests pass:
Use `.toEqual` when you want to check that two objects have the same value. This matcher recursively checks the equality of all fields, rather than checking for object identity—this is also known as "deep equal". For example, `toEqual` and `toBe` behave differently in this test suite, so all the tests pass:

```js
const can1 = {
Expand Down
9 changes: 2 additions & 7 deletions docs/ManualMocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@ next: webpack

Manual mocks are used to stub out functionality with mock data. For example, instead of accessing a remote resource like a website or a database, you might want to create a manual mock that allows you to use fake data. This ensures your tests will be fast and not flaky.

Manual mocks are defined by writing a module in a `__mocks__/` subdirectory
immediately adjacent to the module. For example, to mock a module called
``user`` in the ``models`` directory, create a file called ``user.js`` and
put it in the ``models/__mocks__`` directory. If the module you are mocking is
a node module (eg: `fs`), the mock should be placed in the same parent
directory as the ``node_modules`` folder. Eg:
Manual mocks are defined by writing a module in a `__mocks__/` subdirectory immediately adjacent to the module. For example, to mock a module called `user` in the `models` directory, create a file called `user.js` and put it in the `models/__mocks__` directory. If the module you are mocking is a node module (eg: `fs`), the mock should be placed in the `__mocks__` directory adjacent to `node_modules`. Eg:

```bash
.
├── config
├── fs.js
├── __mocks__
│   └── fs.js
├── models
│   ├── __mocks__
│   │   └── user.js
Expand Down
2 changes: 1 addition & 1 deletion docs/SnapshotTesting.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ exports[`Link renders correctly 1`] = `
`;
```

The snapshot artifact should be committed alongside code changes. Jest uses [pretty-format](https://github.com/facebook/jest/tree/master/packages/pretty-format) to make snapshots human-readable during code review. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code that should be fixed, or the implementation has changed and the snapshot needs to be updated.
The snapshot artifact should be committed alongside code changes, and reviewed as part of your code review process. Jest uses [pretty-format](https://github.com/facebook/jest/tree/master/packages/pretty-format) to make snapshots human-readable during code review. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code that should be fixed, or the implementation has changed and the snapshot needs to be updated.

More information on how snapshot testing works and why we built it can be found on the [release blog post](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html). We recommend reading [this blog post](http://benmccormick.org/2016/09/19/testing-with-jest-snapshots-first-impressions/) to get a good sense of when you should use snapshot testing. We also recommend watching this [this egghead video](https://egghead.io/lessons/javascript-use-jest-s-snapshot-testing-feature?pl=testing-javascript-with-jest-a36c4074) on Snapshot Testing with Jest.

Expand Down
9 changes: 3 additions & 6 deletions docs/TestingAsyncCode.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,13 @@ If `done()` is never called, the test will fail, which is what you want to happe

### Promises

If your code uses promises, there is a simpler way to handle asynchronous tests. Just return a promise from your test, and Jest will wait for that promise to resolve. If the promise is rejected, the test will automatically fail.
If your code uses promises, there is a simpler way to handle asynchronous tests. Just use the `resolves` keyword in your expect statement, and Jest will wait for that promise to resolve. If the promise is rejected, the test will automatically fail.

For example, let's say that `fetchData`, instead of using a callback, returns a promise that is supposed to resolve to the string `"peanut butter"`. We could test it with:

```js
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
return expect(fetchData()).resolves.toBe('peanut butter');
});
```

Expand All @@ -68,8 +66,7 @@ If your code uses `async` and `await`, you can use these in your tests as well.

```js
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
await expect(fetchData()).resolves.toBe('peanut butter');
});
```

Expand Down
33 changes: 10 additions & 23 deletions docs/TutorialAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function request(url) {
}
```

Now let's write a test for our async functionality.
Now let's write a test for our async functionality. Using the `resolves` keyword
```js
// __tests__/user-test.js
jest.mock('../request');
Expand All @@ -77,8 +77,7 @@ import * as user from '../user';

// The promise that is being tested should be returned.
it('works with promises', () => {
return user.getUserName(5)
.then(name => expect(name).toEqual('Paul'));
return expect(user.getUserName(5)).resolves.toEqual('Paul');
});
```

Expand All @@ -94,8 +93,7 @@ how you'd write the same example from before:
```js
// async/await can also be used.
it('works with async/await', async () => {
const userName = await user.getUserName(4);
expect(userName).toEqual('Mark');
await expect(user.getUserName(4)).resolves.toEqual('Mark');
});
```

Expand All @@ -106,32 +104,21 @@ and enable the feature in your `.babelrc` file.

### Error handling

Errors can be handled in the standard JavaScript way: Either using `.catch()`
directly on a Promise or through `try-catch` when using async/await. Note that
if a Promise throws and the error is not handled, the test will fail. `expect.assertion(1)` makes sure that expectation was checked once. In this example it will fail if promise was resolved without throwing.
Errors can be handled using the keyword `rejects` in your expect statement. This will verify that the promise rejects and perform an assertion on the resulting error.

```js
// Testing for async errors can be done using `catch`.
it('tests error with promises', () => {
// to be sure that `Promise` rejected and `expect` has been called once
expect.assertions(1);

return user.getUserName(3)
.catch(e => expect(e).toEqual({
error: 'User with 3 not found.',
}));
return expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});

// Or try-catch.
it('tests error with async/await', async () => {
// to be sure that `await` throws error and `expect` has been called once
expect.assertions(1);

try {
await user.getUserName(2);
} catch (object) {
expect(object.error).toEqual('User with 2 not found.');
}
await expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`mocks async functions 1`] = `
Object {
"rest": " PASS __tests__/native-async-mock-test.js
mock works with native async
",
"summary": "Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites.
",
}
`;
24 changes: 20 additions & 4 deletions integration_tests/__tests__/failures-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,30 @@ const dir = path.resolve(__dirname, '../failures');

skipOnWindows.suite();

// Some node versions add an extra line to the error stack trace. This makes
// snapshot tests fail on different machines. This function makes sure
// this extra line is always removed.
const stripInconsistentStackLines = summary => {
summary.rest = summary.rest.replace(/\n^.*process\._tickCallback.*$/gm, '');
return summary;
};

test('throwing not Error objects', () => {
let stderr;
stderr = runJest(dir, ['throw-number-test.js']).stderr;
expect(extractSummary(stderr)).toMatchSnapshot();
expect(stripInconsistentStackLines(
extractSummary(stderr),
)).toMatchSnapshot();
stderr = runJest(dir, ['throw-string-test.js']).stderr;
expect(extractSummary(stderr)).toMatchSnapshot();
expect(stripInconsistentStackLines(
extractSummary(stderr),
)).toMatchSnapshot();
stderr = runJest(dir, ['throw-object-test.js']).stderr;
expect(extractSummary(stderr)).toMatchSnapshot();
expect(stripInconsistentStackLines(
extractSummary(stderr),
)).toMatchSnapshot();
stderr = runJest(dir, ['assertion-count-test.js']).stderr;
expect(extractSummary(stderr)).toMatchSnapshot();
expect(stripInconsistentStackLines(
extractSummary(stderr),
)).toMatchSnapshot();
});
28 changes: 28 additions & 0 deletions integration_tests/__tests__/native-async-mock-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

'use strict';

const {linkJestPackage, run} = require('../utils');
const {extractSummary} = require('../utils');
const path = require('path');
const runJest = require('../runJest');
const skipOnWindows = require('skipOnWindows');

skipOnWindows.suite();
const dir = path.resolve(__dirname, '..', 'native-async-mock');

test('mocks async functions', () => {
if (process.platform !== 'win32') {
run('npm install', dir);
linkJestPackage('babel-jest', dir);
}
// --no-cache because babel can cache stuff and result in false green
const {stderr} = runJest(dir, ['--no-cache']);
expect(extractSummary(stderr)).toMatchSnapshot();
});
4 changes: 4 additions & 0 deletions integration_tests/native-async-mock/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["es2015"],
"plugins": ["transform-async-to-generator"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2004-present Facebook. All Rights Reserved.

'use strict';

jest.mock('../native');

const native = require('../native');

test('mock works with native async', () => {
expect(native.asyncMethod).toBeDefined();
});
14 changes: 14 additions & 0 deletions integration_tests/native-async-mock/native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2004-present Facebook. All Rights Reserved.

'use strict';

function awaitable() {
return Promise.resolve();
}

module.exports.syncMethod = () => 42;

module.exports.asyncMethod = async () => {
await awaitable();
return 42;
};
9 changes: 9 additions & 0 deletions integration_tests/native-async-mock/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"jest": {
"testEnvironment": "node"
},
"dependencies": {
"babel-plugin-transform-async-to-generator": "^6.22.0",
"babel-preset-es2015": "^6.24.0"
}
}
14 changes: 7 additions & 7 deletions packages/jest-cli/src/SearchSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
'use strict';

import type {Config} from 'types/Config';
import type {HasteContext} from 'types/HasteMap';
import type {Context} from 'types/Context';
import type {Glob, Path} from 'types/Config';
import type {ResolveModuleConfig} from 'types/Resolve';

Expand Down Expand Up @@ -86,7 +86,7 @@ const regexToMatcher = (testRegex: string) => {
};

class SearchSource {
_hasteContext: HasteContext;
_context: Context;
_config: SearchSourceConfig;
_options: ResolveModuleConfig;
_rootPattern: RegExp;
Expand All @@ -99,11 +99,11 @@ class SearchSource {
};

constructor(
hasteMap: HasteContext,
context: Context,
config: SearchSourceConfig,
options?: ResolveModuleConfig,
) {
this._hasteContext = hasteMap;
this._context = context;
this._config = config;
this._options = options || {
skipNodeResolution: false,
Expand Down Expand Up @@ -164,7 +164,7 @@ class SearchSource {

_getAllTestPaths(testPathPattern: StrOrRegExpPattern): SearchResult {
return this._filterTestPathsWithStats(
this._hasteContext.hasteFS.getAllFiles(),
this._context.hasteFS.getAllFiles(),
testPathPattern,
);
}
Expand All @@ -180,8 +180,8 @@ class SearchSource {

findRelatedTests(allPaths: Set<Path>): SearchResult {
const dependencyResolver = new DependencyResolver(
this._hasteContext.resolver,
this._hasteContext.hasteFS,
this._context.resolver,
this._context.hasteFS,
);
return {
paths: dependencyResolver.resolveInverse(
Expand Down
Loading

0 comments on commit ec3a6a0

Please sign in to comment.