Installing dependencies.
This commit is contained in:
+89
@@ -0,0 +1,89 @@
|
||||
# Have control over `test` and `it` usages (`consistent-test-it`)
|
||||
|
||||
Jest allows you to choose how you want to define your tests, using the `it` or
|
||||
the `test` keywords, with multiple permutations for each:
|
||||
|
||||
- **it:** `it`, `xit`, `fit`, `it.only`, `it.skip`.
|
||||
- **test:** `test`, `xtest`, `test.only`, `test.skip`.
|
||||
|
||||
This rule gives you control over the usage of these keywords in your codebase.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule can be configured as follows
|
||||
|
||||
```json5
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
fn: {
|
||||
enum: ['it', 'test'],
|
||||
},
|
||||
withinDescribe: {
|
||||
enum: ['it', 'test'],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}
|
||||
```
|
||||
|
||||
#### fn
|
||||
|
||||
Decides whether to use `test` or `it`.
|
||||
|
||||
#### withinDescribe
|
||||
|
||||
Decides whether to use `test` or `it` within a `describe` scope.
|
||||
|
||||
```js
|
||||
/*eslint jest/consistent-test-it: ["error", {"fn": "test"}]*/
|
||||
|
||||
test('foo'); // valid
|
||||
test.only('foo'); // valid
|
||||
|
||||
it('foo'); // invalid
|
||||
it.only('foo'); // invalid
|
||||
```
|
||||
|
||||
```js
|
||||
/*eslint jest/consistent-test-it: ["error", {"fn": "it"}]*/
|
||||
|
||||
it('foo'); // valid
|
||||
it.only('foo'); // valid
|
||||
|
||||
test('foo'); // invalid
|
||||
test.only('foo'); // invalid
|
||||
```
|
||||
|
||||
```js
|
||||
/*eslint jest/consistent-test-it: ["error", {"fn": "it", "withinDescribe": "test"}]*/
|
||||
|
||||
it('foo'); // valid
|
||||
describe('foo', function () {
|
||||
test('bar'); // valid
|
||||
});
|
||||
|
||||
test('foo'); // invalid
|
||||
describe('foo', function () {
|
||||
it('bar'); // invalid
|
||||
});
|
||||
```
|
||||
|
||||
### Default configuration
|
||||
|
||||
The default configuration forces all top-level tests to use `test` and all tests
|
||||
nested within `describe` to use `it`.
|
||||
|
||||
```js
|
||||
/*eslint jest/consistent-test-it: ["error"]*/
|
||||
|
||||
test('foo'); // valid
|
||||
describe('foo', function () {
|
||||
it('bar'); // valid
|
||||
});
|
||||
|
||||
it('foo'); // invalid
|
||||
describe('foo', function () {
|
||||
test('bar'); // invalid
|
||||
});
|
||||
```
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
# Enforce assertion to be made in a test body (`expect-expect`)
|
||||
|
||||
Ensure that there is at least one `expect` call made in a test.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers when there is no call made to `expect` in a test, to prevent
|
||||
users from forgetting to add assertions.
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
it('should be a test', () => {
|
||||
console.log('no assertion');
|
||||
});
|
||||
test('should assert something', () => {});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
it('should be a test', () => {
|
||||
expect(true).toBeDefined();
|
||||
});
|
||||
it('should work with callbacks/async', () => {
|
||||
somePromise().then(res => expect(res).toBe('passed'));
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{
|
||||
"assertFunctionNames": ["expect"],
|
||||
"additionalTestBlockFunctions": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `assertFunctionNames`
|
||||
|
||||
This array option specifies the names of functions that should be considered to
|
||||
be asserting functions. Function names can use wildcards i.e `request.*.expect`,
|
||||
`request.**.expect`, `request.*.expect*`
|
||||
|
||||
Examples of **incorrect** code for the `{ "assertFunctionNames": ["expect"] }`
|
||||
option:
|
||||
|
||||
```js
|
||||
/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect"] }] */
|
||||
|
||||
import { expectSaga } from 'redux-saga-test-plan';
|
||||
import { addSaga } from '../src/sagas';
|
||||
|
||||
test('returns sum', () => {
|
||||
expectSaga(addSaga, 1, 1).returns(2).run();
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for the
|
||||
`{ "assertFunctionNames": ["expect", "expectSaga"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect", "expectSaga"] }] */
|
||||
|
||||
import { expectSaga } from 'redux-saga-test-plan';
|
||||
import { addSaga } from '../src/sagas';
|
||||
|
||||
test('returns sum', () => {
|
||||
expectSaga(addSaga, 1, 1).returns(2).run();
|
||||
});
|
||||
```
|
||||
|
||||
Since the string is compiled into a regular expression, you'll need to escape
|
||||
special characters such as `$` with a double backslash:
|
||||
|
||||
```js
|
||||
/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect\\$"] }] */
|
||||
|
||||
it('is money-like', () => {
|
||||
expect$(1.0);
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for working with the HTTP assertions library
|
||||
[SuperTest](https://www.npmjs.com/package/supertest) with the
|
||||
`{ "assertFunctionNames": ["expect", "request.**.expect"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect", "request.**.expect"] }] */
|
||||
const request = require('supertest');
|
||||
const express = require('express');
|
||||
|
||||
const app = express();
|
||||
|
||||
describe('GET /user', function () {
|
||||
it('responds with json', function (done) {
|
||||
request(app).get('/user').expect('Content-Type', /json/).expect(200, done);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### `additionalTestBlockFunctions`
|
||||
|
||||
This array can be used to specify the names of functions that should also be
|
||||
treated as test blocks:
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{ "additionalTestBlockFunctions": ["theoretically"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following is _correct_ when using the above configuration:
|
||||
|
||||
```js
|
||||
import theoretically from 'jest-theories';
|
||||
|
||||
describe('NumberToLongString', () => {
|
||||
const theories = [
|
||||
{ input: 100, expected: 'One hundred' },
|
||||
{ input: 1000, expected: 'One thousand' },
|
||||
{ input: 10000, expected: 'Ten thousand' },
|
||||
{ input: 100000, expected: 'One hundred thousand' },
|
||||
];
|
||||
|
||||
theoretically(
|
||||
'the number {input} is correctly translated to string',
|
||||
theories,
|
||||
theory => {
|
||||
const output = NumberToLongString(theory.input);
|
||||
expect(output).toBe(theory.expected);
|
||||
},
|
||||
);
|
||||
});
|
||||
```
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# Enforces a maximum number assertion calls in a test body (`max-expects`)
|
||||
|
||||
As more assertions are made, there is a possible tendency for the test to be
|
||||
more likely to mix multiple objectives. To avoid this, this rule reports when
|
||||
the maximum number of assertions is exceeded.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule enforces a maximum number of `expect()` calls.
|
||||
|
||||
The following patterns are considered warnings (with the default option of
|
||||
`{ "max": 5 } `):
|
||||
|
||||
```js
|
||||
test('should not pass', () => {
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
});
|
||||
|
||||
it('should not pass', () => {
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns are **not** considered warnings (with the default option
|
||||
of `{ "max": 5 } `):
|
||||
|
||||
```js
|
||||
test('shout pass');
|
||||
|
||||
test('shout pass', () => {});
|
||||
|
||||
test.skip('shout pass', () => {});
|
||||
|
||||
test('should pass', function () {
|
||||
expect(true).toBeDefined();
|
||||
});
|
||||
|
||||
test('should pass', () => {
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
expect(true).toBeDefined();
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/max-expects": [
|
||||
"error",
|
||||
{
|
||||
"max": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `max`
|
||||
|
||||
Enforces a maximum number of `expect()`.
|
||||
|
||||
This has a default value of `5`.
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
# Enforces a maximum depth to nested describe calls (`max-nested-describe`)
|
||||
|
||||
While it's useful to be able to group your tests together within the same file
|
||||
using `describe()`, having too many levels of nesting throughout your tests make
|
||||
them difficult to read.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule enforces a maximum depth to nested `describe()` calls to improve code
|
||||
clarity in your tests.
|
||||
|
||||
The following patterns are considered warnings (with the default option of
|
||||
`{ "max": 5 } `):
|
||||
|
||||
```js
|
||||
describe('foo', () => {
|
||||
describe('bar', () => {
|
||||
describe('baz', () => {
|
||||
describe('qux', () => {
|
||||
describe('quxx', () => {
|
||||
describe('too many', () => {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('foo', function () {
|
||||
describe('bar', function () {
|
||||
describe('baz', function () {
|
||||
describe('qux', function () {
|
||||
describe('quxx', function () {
|
||||
describe('too many', function () {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns are **not** considered warnings (with the default option
|
||||
of `{ "max": 5 } `):
|
||||
|
||||
```js
|
||||
describe('foo', () => {
|
||||
describe('bar', () => {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
|
||||
describe('qux', () => {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('foo2', function () {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
|
||||
describe('foo', function () {
|
||||
describe('bar', function () {
|
||||
describe('baz', function () {
|
||||
describe('qux', function () {
|
||||
describe('this is the limit', function () {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/max-nested-describe": [
|
||||
"error",
|
||||
{
|
||||
"max": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `max`
|
||||
|
||||
Enforces a maximum depth for nested `describe()`.
|
||||
|
||||
This has a default value of `5`.
|
||||
|
||||
Examples of patterns **not** considered warnings with options set to
|
||||
`{ "max": 2 }`:
|
||||
|
||||
```js
|
||||
describe('foo', () => {
|
||||
describe('bar', () => {
|
||||
it('should get something', () => {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('foo2', function () {
|
||||
describe('bar2', function () {
|
||||
it('should get something', function () {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
|
||||
it('should get else', function () {
|
||||
expect(getSomething()).toBe('Something');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Disallow alias methods (`no-alias-methods`)
|
||||
|
||||
Several Jest methods have alias names, such as `toThrow` having the alias of
|
||||
`toThrowError`. This rule ensures that only the canonical name as used in the
|
||||
Jest documentation is used in the code. This makes it easier to search for all
|
||||
occurrences of the method within code, and it ensures consistency among the
|
||||
method names used.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if the alias name, rather than the canonical name,
|
||||
of a method is used.
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
expect(a).toBeCalled();
|
||||
expect(a).toBeCalledTimes();
|
||||
expect(a).toBeCalledWith();
|
||||
expect(a).lastCalledWith();
|
||||
expect(a).nthCalledWith();
|
||||
expect(a).toReturn();
|
||||
expect(a).toReturnTimes();
|
||||
expect(a).toReturnWith();
|
||||
expect(a).lastReturnedWith();
|
||||
expect(a).nthReturnedWith();
|
||||
expect(a).toThrowError();
|
||||
```
|
||||
|
||||
The following patterns are not considered warnings:
|
||||
|
||||
```js
|
||||
expect(a).toHaveBeenCalled();
|
||||
expect(a).toHaveBeenCalledTimes();
|
||||
expect(a).toHaveBeenCalledWith();
|
||||
expect(a).toHaveBeenLastCalledWith();
|
||||
expect(a).toHaveBeenNthCalledWith();
|
||||
expect(a).toHaveReturned();
|
||||
expect(a).toHaveReturnedTimes();
|
||||
expect(a).toHaveReturnedWith();
|
||||
expect(a).toHaveLastReturnedWith();
|
||||
expect(a).toHaveNthReturnedWith();
|
||||
expect(a).toThrow();
|
||||
```
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
# Disallow commented out tests (`no-commented-out-tests`)
|
||||
|
||||
This rule raises a warning about commented out tests. It's similar to
|
||||
no-disabled-tests rule.
|
||||
|
||||
## Rule Details
|
||||
|
||||
The rule uses fuzzy matching to do its best to determine what constitutes a
|
||||
commented out test, checking for a presence of `it(`, `describe(`, `it.skip(`,
|
||||
etc. in code comments.
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
// describe('foo', () => {});
|
||||
// it('foo', () => {});
|
||||
// test('foo', () => {});
|
||||
|
||||
// describe.skip('foo', () => {});
|
||||
// it.skip('foo', () => {});
|
||||
// test.skip('foo', () => {});
|
||||
|
||||
// describe['skip']('bar', () => {});
|
||||
// it['skip']('bar', () => {});
|
||||
// test['skip']('bar', () => {});
|
||||
|
||||
// xdescribe('foo', () => {});
|
||||
// xit('foo', () => {});
|
||||
// xtest('foo', () => {});
|
||||
|
||||
/*
|
||||
describe('foo', () => {});
|
||||
*/
|
||||
```
|
||||
|
||||
These patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
describe('foo', () => {});
|
||||
it('foo', () => {});
|
||||
test('foo', () => {});
|
||||
|
||||
describe.only('bar', () => {});
|
||||
it.only('bar', () => {});
|
||||
test.only('bar', () => {});
|
||||
|
||||
// foo('bar', () => {});
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
The plugin looks at the literal function names within test code, so will not
|
||||
catch more complex examples of commented out tests, such as:
|
||||
|
||||
```js
|
||||
// const testSkip = test.skip;
|
||||
// testSkip('skipped test', () => {});
|
||||
|
||||
// const myTest = test;
|
||||
// myTest('does not have function body');
|
||||
```
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
# Prevent calling `expect` conditionally (`no-conditional-expect`)
|
||||
|
||||
This rule prevents the use of `expect` in conditional blocks, such as `if`s &
|
||||
`catch`s.
|
||||
|
||||
This includes using `expect` in callbacks to functions named `catch`, which are
|
||||
assumed to be promises.
|
||||
|
||||
## Rule Details
|
||||
|
||||
Jest only considers a test to have failed if it throws an error, meaning if
|
||||
calls to assertion functions like `expect` occur in conditional code such as a
|
||||
`catch` statement, tests can end up passing but not actually test anything.
|
||||
|
||||
Additionally, conditionals tend to make tests more brittle and complex, as they
|
||||
increase the amount of mental thinking needed to understand what is actually
|
||||
being tested.
|
||||
|
||||
While `expect.assertions` & `expect.hasAssertions` can help prevent tests from
|
||||
silently being skipped, when combined with conditionals they typically result in
|
||||
even more complexity being introduced.
|
||||
|
||||
The following patterns are warnings:
|
||||
|
||||
```js
|
||||
it('foo', () => {
|
||||
doTest && expect(1).toBe(2);
|
||||
});
|
||||
|
||||
it('bar', () => {
|
||||
if (!skipTest) {
|
||||
expect(1).toEqual(2);
|
||||
}
|
||||
});
|
||||
|
||||
it('baz', async () => {
|
||||
try {
|
||||
await foo();
|
||||
} catch (err) {
|
||||
expect(err).toMatchObject({ code: 'MODULE_NOT_FOUND' });
|
||||
}
|
||||
});
|
||||
|
||||
it('throws an error', async () => {
|
||||
await foo().catch(error => expect(error).toBeInstanceOf(error));
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns are not warnings:
|
||||
|
||||
```js
|
||||
it('foo', () => {
|
||||
expect(!value).toBe(false);
|
||||
});
|
||||
|
||||
function getValue() {
|
||||
if (process.env.FAIL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
it('foo', () => {
|
||||
expect(getValue()).toBe(2);
|
||||
});
|
||||
|
||||
it('validates the request', () => {
|
||||
try {
|
||||
processRequest(request);
|
||||
} catch {
|
||||
// ignore errors
|
||||
} finally {
|
||||
expect(validRequest).toHaveBeenCalledWith(request);
|
||||
}
|
||||
});
|
||||
|
||||
it('throws an error', async () => {
|
||||
await expect(foo).rejects.toThrow(Error);
|
||||
});
|
||||
```
|
||||
|
||||
### How to catch a thrown error for testing without violating this rule
|
||||
|
||||
A common situation that comes up with this rule is when wanting to test
|
||||
properties on a thrown error, as Jest's `toThrow` matcher only checks the
|
||||
`message` property.
|
||||
|
||||
Most people write something like this:
|
||||
|
||||
```typescript
|
||||
describe('when the http request fails', () => {
|
||||
it('includes the status code in the error', async () => {
|
||||
try {
|
||||
await makeRequest(url);
|
||||
} catch (error) {
|
||||
expect(error).toHaveProperty('statusCode', 404);
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
As stated above, the problem with this is that if `makeRequest()` doesn't throw
|
||||
the test will still pass as if the `expect` had been called.
|
||||
|
||||
While you can use `expect.assertions` & `expect.hasAssertions` for these
|
||||
situations, they only work with `expect`.
|
||||
|
||||
A better way to handle this situation is to introduce a wrapper to handle the
|
||||
catching, and otherwise return a specific "no error thrown" error if nothing is
|
||||
thrown by the wrapped function:
|
||||
|
||||
```typescript
|
||||
class NoErrorThrownError extends Error {}
|
||||
|
||||
const getError = async <TError>(call: () => unknown): Promise<TError> => {
|
||||
try {
|
||||
await call();
|
||||
|
||||
throw new NoErrorThrownError();
|
||||
} catch (error: unknown) {
|
||||
return error as TError;
|
||||
}
|
||||
};
|
||||
|
||||
describe('when the http request fails', () => {
|
||||
it('includes the status code in the error', async () => {
|
||||
const error = await getError(async () => makeRequest(url));
|
||||
|
||||
// check that the returned error wasn't that no error was thrown
|
||||
expect(error).not.toBeInstanceOf(NoErrorThrownError);
|
||||
expect(error).toHaveProperty('statusCode', 404);
|
||||
});
|
||||
});
|
||||
```
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
# Disallow conditional logic in tests (`no-conditional-in-test`)
|
||||
|
||||
Conditional logic in tests is usually an indication that a test is attempting to
|
||||
cover too much, and not testing the logic it intends to. Each branch of code
|
||||
executing within a conditional statement will usually be better served by a test
|
||||
devoted to it.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule reports on any use of a conditional statement such as `if`, `switch`,
|
||||
and ternary expressions.
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
it('foo', () => {
|
||||
if (true) {
|
||||
doTheThing();
|
||||
}
|
||||
});
|
||||
|
||||
it('bar', () => {
|
||||
switch (mode) {
|
||||
case 'none':
|
||||
generateNone();
|
||||
case 'single':
|
||||
generateOne();
|
||||
case 'multiple':
|
||||
generateMany();
|
||||
}
|
||||
|
||||
expect(fixtures.length).toBeGreaterThan(-1);
|
||||
});
|
||||
|
||||
it('baz', async () => {
|
||||
const promiseValue = () => {
|
||||
return something instanceof Promise
|
||||
? something
|
||||
: Promise.resolve(something);
|
||||
};
|
||||
|
||||
await expect(promiseValue()).resolves.toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
describe('my tests', () => {
|
||||
if (true) {
|
||||
it('foo', () => {
|
||||
doTheThing();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
switch (mode) {
|
||||
case 'none':
|
||||
generateNone();
|
||||
case 'single':
|
||||
generateOne();
|
||||
case 'multiple':
|
||||
generateMany();
|
||||
}
|
||||
});
|
||||
|
||||
it('bar', () => {
|
||||
expect(fixtures.length).toBeGreaterThan(-1);
|
||||
});
|
||||
|
||||
const promiseValue = something => {
|
||||
return something instanceof Promise ? something : Promise.resolve(something);
|
||||
};
|
||||
|
||||
it('baz', async () => {
|
||||
await expect(promiseValue()).resolves.toBe(1);
|
||||
});
|
||||
```
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Disallow use of deprecated functions (`no-deprecated-functions`)
|
||||
|
||||
Over the years Jest has accrued some debt in the form of functions that have
|
||||
either been renamed for clarity, or replaced with more powerful APIs.
|
||||
|
||||
While typically these deprecated functions are kept in the codebase for a number
|
||||
of majors, eventually they are removed completely.
|
||||
|
||||
This rule requires knowing which version of Jest you're using - see
|
||||
[this section of the readme](../../README.md#jest-version-setting) for details
|
||||
on how that is obtained automatically and how you can explicitly provide a
|
||||
version if needed.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule warns about calls to deprecated functions, and provides details on
|
||||
what to replace them with, based on the version of Jest that is installed.
|
||||
|
||||
This rule can also autofix a number of these deprecations for you.
|
||||
|
||||
### `jest.resetModuleRegistry`
|
||||
|
||||
This function was renamed to `resetModules` in Jest 15, and is scheduled for
|
||||
removal in Jest 27.
|
||||
|
||||
### `jest.addMatchers`
|
||||
|
||||
This function was replaced with `expect.extend` in Jest 17, and is scheduled for
|
||||
removal in Jest 27.
|
||||
|
||||
### `require.requireActual` & `require.requireMock`
|
||||
|
||||
These functions were replaced in Jest 21 and removed in Jest 26.
|
||||
|
||||
Originally, the `requireActual` & `requireMock` the `requireActual`&
|
||||
`requireMock` functions were placed onto the `require` function.
|
||||
|
||||
These functions were later moved onto the `jest` object in order to be easier
|
||||
for type checkers to handle, and their use via `require` deprecated. Finally,
|
||||
the release of Jest 26 saw them removed from the `require` function altogether.
|
||||
|
||||
### `jest.runTimersToTime`
|
||||
|
||||
This function was renamed to `advanceTimersByTime` in Jest 22, and is scheduled
|
||||
for removal in Jest 27.
|
||||
|
||||
### `jest.genMockFromModule`
|
||||
|
||||
This function was renamed to `createMockFromModule` in Jest 26, and is scheduled
|
||||
for removal in a future version of Jest.
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# Disallow disabled tests (`no-disabled-tests`)
|
||||
|
||||
Jest has a feature that allows you to temporarily mark tests as disabled. This
|
||||
feature is often helpful while debugging or to create placeholders for future
|
||||
tests. Before committing changes we may want to check that all tests are
|
||||
running.
|
||||
|
||||
This rule raises a warning about disabled tests.
|
||||
|
||||
## Rule Details
|
||||
|
||||
There are a number of ways to disable tests in Jest:
|
||||
|
||||
- by appending `.skip` to the test-suite or test-case
|
||||
- by prepending the test function name with `x`
|
||||
- by declaring a test with a name but no function body
|
||||
- by making a call to `pending()` anywhere within the test
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
describe.skip('foo', () => {});
|
||||
it.skip('foo', () => {});
|
||||
test.skip('foo', () => {});
|
||||
|
||||
describe['skip']('bar', () => {});
|
||||
it['skip']('bar', () => {});
|
||||
test['skip']('bar', () => {});
|
||||
|
||||
xdescribe('foo', () => {});
|
||||
xit('foo', () => {});
|
||||
xtest('foo', () => {});
|
||||
|
||||
it('bar');
|
||||
test('bar');
|
||||
|
||||
it('foo', () => {
|
||||
pending();
|
||||
});
|
||||
```
|
||||
|
||||
These patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
describe('foo', () => {});
|
||||
it('foo', () => {});
|
||||
test('foo', () => {});
|
||||
|
||||
describe.only('bar', () => {});
|
||||
it.only('bar', () => {});
|
||||
test.only('bar', () => {});
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
The plugin looks at the literal function names within test code, so will not
|
||||
catch more complex examples of disabled tests, such as:
|
||||
|
||||
```js
|
||||
const testSkip = test.skip;
|
||||
testSkip('skipped test', () => {});
|
||||
|
||||
const myTest = test;
|
||||
myTest('does not have function body');
|
||||
```
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Avoid using a callback in asynchronous tests and hooks (`no-done-callback`)
|
||||
|
||||
When calling asynchronous code in hooks and tests, `jest` needs to know when the
|
||||
asynchronous work is complete to progress the current run.
|
||||
|
||||
Originally the most common pattern to achieve this was to use callbacks:
|
||||
|
||||
```js
|
||||
test('the data is peanut butter', done => {
|
||||
function callback(data) {
|
||||
try {
|
||||
expect(data).toBe('peanut butter');
|
||||
done();
|
||||
} catch (error) {
|
||||
done(error);
|
||||
}
|
||||
}
|
||||
|
||||
fetchData(callback);
|
||||
});
|
||||
```
|
||||
|
||||
This can be very error-prone however, as it requires careful understanding of
|
||||
how assertions work in tests or otherwise tests won't behave as expected.
|
||||
|
||||
For example, if the `try/catch` was left out of the above code, the test would
|
||||
time out rather than fail. Even with the `try/catch`, forgetting to pass the
|
||||
caught error to `done` will result in `jest` believing the test has passed.
|
||||
|
||||
A more straightforward way to handle asynchronous code is to use Promises:
|
||||
|
||||
```js
|
||||
test('the data is peanut butter', () => {
|
||||
return fetchData().then(data => {
|
||||
expect(data).toBe('peanut butter');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
When a test or hook returns a promise, `jest` waits for that promise to resolve,
|
||||
as well as automatically failing should the promise reject.
|
||||
|
||||
If your environment supports `async/await`, this becomes even simpler:
|
||||
|
||||
```js
|
||||
test('the data is peanut butter', async () => {
|
||||
const data = await fetchData();
|
||||
expect(data).toBe('peanut butter');
|
||||
});
|
||||
```
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule checks the function parameter of hooks & tests for use of the `done`
|
||||
argument, suggesting you return a promise instead.
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
beforeEach(done => {
|
||||
// ...
|
||||
});
|
||||
|
||||
test('myFunction()', done => {
|
||||
// ...
|
||||
});
|
||||
|
||||
test('myFunction()', function (done) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns are not considered warnings:
|
||||
|
||||
```js
|
||||
beforeEach(async () => {
|
||||
await setupUsTheBomb();
|
||||
});
|
||||
|
||||
test('myFunction()', () => {
|
||||
expect(myFunction()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('myFunction()', () => {
|
||||
return new Promise(done => {
|
||||
expect(myFunction()).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
```
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
# Disallow duplicate setup and teardown hooks (`no-duplicate-hooks`)
|
||||
|
||||
A `describe` block should not contain duplicate hooks.
|
||||
|
||||
## Rule Details
|
||||
|
||||
Examples of **incorrect** code for this rule
|
||||
|
||||
```js
|
||||
/* eslint jest/no-duplicate-hooks: "error" */
|
||||
|
||||
describe('foo', () => {
|
||||
beforeEach(() => {
|
||||
// some setup
|
||||
});
|
||||
beforeEach(() => {
|
||||
// some setup
|
||||
});
|
||||
test('foo_test', () => {
|
||||
// some test
|
||||
});
|
||||
});
|
||||
|
||||
// Nested describe scenario
|
||||
describe('foo', () => {
|
||||
beforeEach(() => {
|
||||
// some setup
|
||||
});
|
||||
test('foo_test', () => {
|
||||
// some test
|
||||
});
|
||||
describe('bar', () => {
|
||||
test('bar_test', () => {
|
||||
afterAll(() => {
|
||||
// some teardown
|
||||
});
|
||||
afterAll(() => {
|
||||
// some teardown
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule
|
||||
|
||||
```js
|
||||
/* eslint jest/no-duplicate-hooks: "error" */
|
||||
|
||||
describe('foo', () => {
|
||||
beforeEach(() => {
|
||||
// some setup
|
||||
});
|
||||
test('foo_test', () => {
|
||||
// some test
|
||||
});
|
||||
});
|
||||
|
||||
// Nested describe scenario
|
||||
describe('foo', () => {
|
||||
beforeEach(() => {
|
||||
// some setup
|
||||
});
|
||||
test('foo_test', () => {
|
||||
// some test
|
||||
});
|
||||
describe('bar', () => {
|
||||
test('bar_test', () => {
|
||||
beforeEach(() => {
|
||||
// some setup
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Disallow using `exports` in files containing tests (`no-export`)
|
||||
|
||||
Prevents using `exports` if a file has one or more tests in it.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule aims to eliminate duplicate runs of tests by exporting things from
|
||||
test files. If you import from a test file, then all the tests in that file will
|
||||
be run in each imported instance, so bottom line, don't export from a test, but
|
||||
instead move helper functions into a separate file when they need to be shared
|
||||
across tests.
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
export function myHelper() {}
|
||||
|
||||
module.exports = function () {};
|
||||
|
||||
module.exports = {
|
||||
something: 'that should be moved to a non-test file',
|
||||
};
|
||||
|
||||
describe('a test', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
function myHelper() {}
|
||||
|
||||
const myThing = {
|
||||
something: 'that can live here',
|
||||
};
|
||||
|
||||
describe('a test', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
## When Not To Use It
|
||||
|
||||
Don't use this rule on non-jest test files.
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Disallow focused tests (`no-focused-tests`)
|
||||
|
||||
Jest has a feature that allows you to focus tests by appending `.only` or
|
||||
prepending `f` to a test-suite or a test-case. This feature is really helpful to
|
||||
debug a failing test, so you don’t have to execute all of your tests. After you
|
||||
have fixed your test and before committing the changes you have to remove
|
||||
`.only` to ensure all tests are executed on your build system.
|
||||
|
||||
This rule reminds you to remove `.only` from your tests by raising a warning
|
||||
whenever you are using the exclusivity feature.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule looks for every `describe.only`, `it.only`, `test.only`, `fdescribe`,
|
||||
and `fit` occurrences within the source code. Of course there are some
|
||||
edge-cases which can’t be detected by this rule e.g.:
|
||||
|
||||
```js
|
||||
const describeOnly = describe.only;
|
||||
describeOnly.apply(describe);
|
||||
```
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
describe.only('foo', () => {});
|
||||
it.only('foo', () => {});
|
||||
describe['only']('bar', () => {});
|
||||
it['only']('bar', () => {});
|
||||
test.only('foo', () => {});
|
||||
test['only']('bar', () => {});
|
||||
fdescribe('foo', () => {});
|
||||
fit('foo', () => {});
|
||||
fit.each`
|
||||
table
|
||||
`();
|
||||
```
|
||||
|
||||
These patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
describe('foo', () => {});
|
||||
it('foo', () => {});
|
||||
describe.skip('bar', () => {});
|
||||
it.skip('bar', () => {});
|
||||
test('foo', () => {});
|
||||
test.skip('bar', () => {});
|
||||
it.each()();
|
||||
it.each`
|
||||
table
|
||||
`();
|
||||
test.each()();
|
||||
test.each`
|
||||
table
|
||||
`();
|
||||
```
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
# Disallow setup and teardown hooks (`no-hooks`)
|
||||
|
||||
Jest provides global functions for setup and teardown tasks, which are called
|
||||
before/after each test case and each test suite. The use of these hooks promotes
|
||||
shared state between tests.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule reports for the following function calls:
|
||||
|
||||
- `beforeAll`
|
||||
- `beforeEach`
|
||||
- `afterAll`
|
||||
- `afterEach`
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
/* eslint jest/no-hooks: "error" */
|
||||
|
||||
function setupFoo(options) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
function setupBar(options) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
describe('foo', () => {
|
||||
let foo;
|
||||
|
||||
beforeEach(() => {
|
||||
foo = setupFoo();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
foo = null;
|
||||
});
|
||||
|
||||
it('does something', () => {
|
||||
expect(foo.doesSomething()).toBe(true);
|
||||
});
|
||||
|
||||
describe('with bar', () => {
|
||||
let bar;
|
||||
|
||||
beforeEach(() => {
|
||||
bar = setupBar();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
bar = null;
|
||||
});
|
||||
|
||||
it('does something with bar', () => {
|
||||
expect(foo.doesSomething(bar)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
/* eslint jest/no-hooks: "error" */
|
||||
|
||||
function setupFoo(options) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
function setupBar(options) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
describe('foo', () => {
|
||||
it('does something', () => {
|
||||
const foo = setupFoo();
|
||||
expect(foo.doesSomething()).toBe(true);
|
||||
});
|
||||
|
||||
it('does something with bar', () => {
|
||||
const foo = setupFoo();
|
||||
const bar = setupBar();
|
||||
expect(foo.doesSomething(bar)).toBe(true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/no-hooks": [
|
||||
"error",
|
||||
{
|
||||
"allow": ["afterEach", "afterAll"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `allow`
|
||||
|
||||
This array option controls which Jest hooks are checked by this rule. There are
|
||||
four possible values:
|
||||
|
||||
- `"beforeAll"`
|
||||
- `"beforeEach"`
|
||||
- `"afterAll"`
|
||||
- `"afterEach"`
|
||||
|
||||
By default, none of these options are enabled (the equivalent of
|
||||
`{ "allow": [] }`).
|
||||
|
||||
Examples of **incorrect** code for the `{ "allow": ["afterEach"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/no-hooks: ["error", { "allow": ["afterEach"] }] */
|
||||
|
||||
function setupFoo(options) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
let foo;
|
||||
|
||||
beforeEach(() => {
|
||||
foo = setupFoo();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
test('foo does this', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
test('foo does that', () => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for the `{ "allow": ["afterEach"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/no-hooks: ["error", { "allow": ["afterEach"] }] */
|
||||
|
||||
function setupFoo(options) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
test('foo does this', () => {
|
||||
const foo = setupFoo();
|
||||
// ...
|
||||
});
|
||||
|
||||
test('foo does that', () => {
|
||||
const foo = setupFoo();
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## When Not To Use It
|
||||
|
||||
If you prefer using the setup and teardown hooks provided by Jest, you can
|
||||
safely disable this rule.
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Jest docs - Setup and Teardown](https://facebook.github.io/jest/docs/en/setup-teardown.html)
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
# Disallow identical titles (`no-identical-title`)
|
||||
|
||||
Having identical titles for two different tests or test suites may create
|
||||
confusion. For example, when a test with the same title as another test in the
|
||||
same test suite fails, it is harder to know which one failed and thus harder to
|
||||
fix.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule looks at the title of every test and test suite. It will report when
|
||||
two test suites or two test cases at the same level of a test suite have the
|
||||
same title.
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
describe('foo', () => {
|
||||
it('should do bar', () => {});
|
||||
it('should do bar', () => {}); // Has the same title as the previous test
|
||||
|
||||
describe('baz', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
describe('baz', () => {
|
||||
// Has the same title as a previous test suite
|
||||
// ...
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
These patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
describe('foo', () => {
|
||||
it('should do foo', () => {});
|
||||
it('should do bar', () => {});
|
||||
|
||||
// Has the same name as a parent test suite, which is fine
|
||||
describe('foo', () => {
|
||||
// Has the same name as a test in a parent test suite, which is fine
|
||||
it('should do foo', () => {});
|
||||
it('should work', () => {});
|
||||
});
|
||||
|
||||
describe('baz', () => {
|
||||
// Has the same title as a previous test suite
|
||||
// Has the same name as a test in a sibling test suite, which is fine
|
||||
it('should work', () => {});
|
||||
});
|
||||
});
|
||||
```
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
# Disallow conditional logic (`no-if`)
|
||||
|
||||
## Deprecated
|
||||
|
||||
This rule has been deprecated in favor of
|
||||
[`no-conditional-in-test`](no-conditional-in-test.md).
|
||||
|
||||
Conditional logic in tests is usually an indication that a test is attempting to
|
||||
cover too much, and not testing the logic it intends to. Each branch of code
|
||||
executing within an if statement will usually be better served by a test devoted
|
||||
to it.
|
||||
|
||||
Conditionals are often used to satisfy the typescript type checker. In these
|
||||
cases, using the non-null assertion operator (!) would be best.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule prevents the use of if/ else statements and conditional (ternary)
|
||||
operations in tests.
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
it('foo', () => {
|
||||
if ('bar') {
|
||||
// an if statement here is invalid
|
||||
// you are probably testing too much
|
||||
}
|
||||
});
|
||||
|
||||
it('foo', () => {
|
||||
const bar = foo ? 'bar' : null;
|
||||
});
|
||||
```
|
||||
|
||||
These patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
it('foo', () => {
|
||||
// only test the 'foo' case
|
||||
});
|
||||
|
||||
it('bar', () => {
|
||||
// test the 'bar' case separately
|
||||
});
|
||||
|
||||
it('foo', () => {
|
||||
function foo(bar) {
|
||||
// nested functions are valid
|
||||
return foo ? bar : null;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## When Not To Use It
|
||||
|
||||
If you do not wish to prevent the use of if statements in tests, you can safely
|
||||
disable this rule.
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# Disallow string interpolation inside snapshots (`no-interpolation-in-snapshots`)
|
||||
|
||||
Prevents the use of string interpolations in snapshots.
|
||||
|
||||
## Rule Details
|
||||
|
||||
Interpolation prevents snapshots from being updated. Instead, properties should
|
||||
be overloaded with a matcher by using
|
||||
[property matchers](https://jestjs.io/docs/en/snapshot-testing#property-matchers).
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
expect(something).toMatchInlineSnapshot(
|
||||
`Object {
|
||||
property: ${interpolated}
|
||||
}`,
|
||||
);
|
||||
|
||||
expect(something).toMatchInlineSnapshot(
|
||||
{ other: expect.any(Number) },
|
||||
`Object {
|
||||
other: Any<Number>,
|
||||
property: ${interpolated}
|
||||
}`,
|
||||
);
|
||||
|
||||
expect(errorThrowingFunction).toThrowErrorMatchingInlineSnapshot(
|
||||
`${interpolated}`,
|
||||
);
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
expect(something).toMatchInlineSnapshot();
|
||||
|
||||
expect(something).toMatchInlineSnapshot(
|
||||
`Object {
|
||||
property: 1
|
||||
}`,
|
||||
);
|
||||
|
||||
expect(something).toMatchInlineSnapshot(
|
||||
{ property: expect.any(Date) },
|
||||
`Object {
|
||||
property: Any<Date>
|
||||
}`,
|
||||
);
|
||||
|
||||
expect(errorThrowingFunction).toThrowErrorMatchingInlineSnapshot();
|
||||
|
||||
expect(errorThrowingFunction).toThrowErrorMatchingInlineSnapshot(
|
||||
`Error Message`,
|
||||
);
|
||||
```
|
||||
|
||||
## When Not To Use It
|
||||
|
||||
Don't use this rule on non-jest test files.
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
# Disallow Jasmine globals (`no-jasmine-globals`)
|
||||
|
||||
`jest` uses `jasmine` as a test runner. A side effect of this is that both a
|
||||
`jasmine` object, and some jasmine-specific globals, are exposed to the test
|
||||
environment. Most functionality offered by Jasmine has been ported to Jest, and
|
||||
the Jasmine globals will stop working in the future. Developers should therefore
|
||||
migrate to Jest's documented API instead of relying on the undocumented Jasmine
|
||||
API.
|
||||
|
||||
### Rule details
|
||||
|
||||
This rule reports on any usage of Jasmine globals, which is not ported to Jest,
|
||||
and suggests alternatives from Jest's own API.
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
|
||||
|
||||
test('my test', () => {
|
||||
pending();
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
fail();
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
spyOn(some, 'object');
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
jasmine.createSpy();
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
expect('foo').toEqual(jasmine.anything());
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
jest.setTimeout(5000);
|
||||
|
||||
test('my test', () => {
|
||||
jest.spyOn(some, 'object');
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
jest.fn();
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
expect('foo').toEqual(expect.anything());
|
||||
});
|
||||
```
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
# Disallow importing Jest (`no-jest-import`)
|
||||
|
||||
The `jest` object is automatically in scope within every test file. The methods
|
||||
in the `jest` object help create mocks and let you control Jest's overall
|
||||
behavior. It is therefore completely unnecessary to import in `jest`, as Jest
|
||||
doesn't export anything in the first place.
|
||||
|
||||
### Rule details
|
||||
|
||||
This rule reports on any importing of Jest.
|
||||
|
||||
To name a few: `var jest = require('jest');` `const jest = require('jest');`
|
||||
`import jest from 'jest';` `import {jest as test} from 'jest';`
|
||||
|
||||
There is no correct usage of this code, other than to not import `jest` in the
|
||||
first place.
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [The Jest Object](https://facebook.github.io/jest/docs/en/jest-object.html)
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
# disallow large snapshots (`no-large-snapshots`)
|
||||
|
||||
When using Jest's snapshot capability one should be mindful of the size of
|
||||
created snapshots. As a general best practice snapshots should be limited in
|
||||
size in order to be more manageable and reviewable. A stored snapshot is only as
|
||||
good as its review and as such keeping it short, sweet, and readable is
|
||||
important to allow for thorough reviews.
|
||||
|
||||
## Usage
|
||||
|
||||
Because Jest snapshots are written with back-ticks (\` \`) which are only valid
|
||||
with
|
||||
[ES2015 onwards](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
|
||||
you should set `parserOptions` in your config to at least allow ES2015 in order
|
||||
to use this rule:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
parserOptions: {
|
||||
ecmaVersion: 2015,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule looks at all Jest inline and external snapshots (files with `.snap`
|
||||
extension) and validates that each stored snapshot within those files does not
|
||||
exceed 50 lines (by default, this is configurable as explained in `Options`
|
||||
section below).
|
||||
|
||||
Example of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
exports[`a large snapshot 1`] = `
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
line 7
|
||||
line 8
|
||||
line 9
|
||||
line 10
|
||||
line 11
|
||||
line 12
|
||||
line 13
|
||||
line 14
|
||||
line 15
|
||||
line 16
|
||||
line 17
|
||||
line 18
|
||||
line 19
|
||||
line 20
|
||||
line 21
|
||||
line 22
|
||||
line 23
|
||||
line 24
|
||||
line 25
|
||||
line 26
|
||||
line 27
|
||||
line 28
|
||||
line 29
|
||||
line 30
|
||||
line 31
|
||||
line 32
|
||||
line 33
|
||||
line 34
|
||||
line 35
|
||||
line 36
|
||||
line 37
|
||||
line 38
|
||||
line 39
|
||||
line 40
|
||||
line 41
|
||||
line 42
|
||||
line 43
|
||||
line 44
|
||||
line 45
|
||||
line 46
|
||||
line 47
|
||||
line 48
|
||||
line 49
|
||||
line 50
|
||||
line 51
|
||||
`;
|
||||
```
|
||||
|
||||
Example of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
exports[`a more manageable and readable snapshot 1`] = `
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
`;
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
This rule has options for modifying the max number of lines allowed for a
|
||||
snapshot:
|
||||
|
||||
In an `eslintrc` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"jest/no-large-snapshots": ["warn", { "maxSize": 12, "inlineMaxSize": 6 }]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Max number of lines allowed could be defined by snapshot type (Inline and
|
||||
External). Use `inlineMaxSize` for
|
||||
[Inline Snapshots](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)
|
||||
size and `maxSize` for
|
||||
[External Snapshots](https://jestjs.io/docs/en/snapshot-testing#snapshot-testing-with-jest).
|
||||
If only `maxSize` is provided on options, the value of `maxSize` will be used
|
||||
for both snapshot types (Inline and External).
|
||||
|
||||
Since `eslint-disable` comments are not preserved by Jest when updating
|
||||
snapshots, you can use the `allowedSnapshots` option to have specific snapshots
|
||||
allowed regardless of their size.
|
||||
|
||||
This option takes a map, with the key being the absolute filepath to a snapshot
|
||||
file, and the value an array of values made up of strings and regular
|
||||
expressions to compare to the names of the snapshots in the `.snap` file when
|
||||
checking if the snapshots size should be allowed.
|
||||
|
||||
Note that regular expressions can only be passed in via `.eslintrc.js` as
|
||||
instances of `RegExp`.
|
||||
|
||||
In an `.eslintrc.js` file:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
rules: {
|
||||
'jest/no-large-snapshots': [
|
||||
'error',
|
||||
{
|
||||
allowedSnapshots: {
|
||||
'/path/to/file.js.snap': ['snapshot name 1', /a big snapshot \d+/],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Since absolute paths are typically not very portable, you can use the builtin
|
||||
`path.resolve` function to expand relative paths into absolutes like so:
|
||||
|
||||
```javascript
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
rules: {
|
||||
'jest/no-large-snapshots': [
|
||||
'error',
|
||||
{
|
||||
allowedSnapshots: {
|
||||
[path.resolve('test/__snapshots__/get.js.snap')]: ['full request'],
|
||||
[path.resolve('test/__snapshots__/put.js.snap')]: ['full request'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Disallow manually importing from `__mocks__` (`no-mocks-import`)
|
||||
|
||||
When using `jest.mock`, your tests (just like the code being tested) should
|
||||
import from `./x`, not `./__mocks__/x`. Not following this rule can lead to
|
||||
confusion, because you will have multiple instances of the mocked module:
|
||||
|
||||
```js
|
||||
jest.mock('./x');
|
||||
const x1 = require('./x');
|
||||
const x2 = require('./__mocks__/x');
|
||||
|
||||
test('x', () => {
|
||||
expect(x1).toBe(x2); // fails! They are both instances of `./__mocks__/x`, but not referentially equal
|
||||
});
|
||||
```
|
||||
|
||||
### Rule details
|
||||
|
||||
This rule reports imports from a path containing a `__mocks__` component.
|
||||
|
||||
Example violations:
|
||||
|
||||
```js
|
||||
import thing from './__mocks__/index';
|
||||
require('./__mocks__/index');
|
||||
require('__mocks__');
|
||||
```
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
# Disallow specific matchers & modifiers (`no-restricted-matchers`)
|
||||
|
||||
This rule bans specific matchers & modifiers from being used, and can suggest
|
||||
alternatives.
|
||||
|
||||
## Rule Details
|
||||
|
||||
Bans are expressed in the form of a map, with the value being either a string
|
||||
message to be shown, or `null` if the default rule message should be used.
|
||||
|
||||
Both matchers, modifiers, and chains of the two are checked, allowing for
|
||||
specific variations of a matcher to be banned if desired.
|
||||
|
||||
By default, this map is empty, meaning no matchers or modifiers are banned.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/no-restricted-matchers": [
|
||||
"error",
|
||||
{
|
||||
"toBeFalsy": null,
|
||||
"resolves": "Use `expect(await promise)` instead.",
|
||||
"not.toHaveBeenCalledWith": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Examples of **incorrect** code for this rule with the above configuration
|
||||
|
||||
```js
|
||||
it('is false', () => {
|
||||
expect(a).toBeFalsy();
|
||||
});
|
||||
|
||||
it('resolves', async () => {
|
||||
await expect(myPromise()).resolves.toBe(true);
|
||||
});
|
||||
|
||||
describe('when an error happens', () => {
|
||||
it('does not upload the file', async () => {
|
||||
expect(uploadFileMock).not.toHaveBeenCalledWith('file.name');
|
||||
});
|
||||
});
|
||||
```
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Disallow using `expect` outside of `it` or `test` blocks (`no-standalone-expect`)
|
||||
|
||||
Prevents `expect` statements outside of a `test` or `it` block. An `expect`
|
||||
within a helper function (but outside of a `test` or `it` block) will not
|
||||
trigger this rule.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule aims to eliminate `expect` statements that will not be executed. An
|
||||
`expect` inside of a `describe` block but outside of a `test` or `it` block or
|
||||
outside a `describe` will not execute and therefore will trigger this rule. It
|
||||
is viable, however, to have an `expect` in a helper function that is called from
|
||||
within a `test` or `it` block so `expect` statements in a function will not
|
||||
trigger this rule.
|
||||
|
||||
Statements like `expect.hasAssertions()` will NOT trigger this rule since these
|
||||
calls will execute if they are not in a test block.
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
// in describe
|
||||
describe('a test', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
|
||||
// below other tests
|
||||
describe('a test', () => {
|
||||
it('an it', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
// in it block
|
||||
describe('a test', () => {
|
||||
it('an it', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
// in helper function
|
||||
describe('a test', () => {
|
||||
const helper = () => {
|
||||
expect(1).toBe(1);
|
||||
};
|
||||
|
||||
it('an it', () => {
|
||||
helper();
|
||||
});
|
||||
});
|
||||
|
||||
describe('a test', () => {
|
||||
expect.hasAssertions(1);
|
||||
});
|
||||
```
|
||||
|
||||
\*Note that this rule will not trigger if the helper function is never used even
|
||||
though the `expect` will not execute. Rely on a rule like no-unused-vars for
|
||||
this case.
|
||||
|
||||
### Options
|
||||
|
||||
#### `additionalTestBlockFunctions`
|
||||
|
||||
This array can be used to specify the names of functions that should also be
|
||||
treated as test blocks:
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"jest/no-standalone-expect": [
|
||||
"error",
|
||||
{ "additionalTestBlockFunctions": ["each.test"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following is _correct_ when using the above configuration:
|
||||
|
||||
```js
|
||||
each([
|
||||
[1, 1, 2],
|
||||
[1, 2, 3],
|
||||
[2, 1, 3],
|
||||
]).test('returns the result of adding %d to %d', (a, b, expected) => {
|
||||
expect(a + b).toBe(expected);
|
||||
});
|
||||
```
|
||||
|
||||
## When Not To Use It
|
||||
|
||||
Don't use this rule on non-jest test files.
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Use `.only` and `.skip` over `f` and `x` (`no-test-prefixes`)
|
||||
|
||||
Jest allows you to choose how you want to define focused and skipped tests, with
|
||||
multiple permutations for each:
|
||||
|
||||
- **only & skip:** `it.only`, `test.only`, `describe.only`, `it.skip`,
|
||||
`test.skip`, `describe.skip`.
|
||||
- **'f' & 'x':** `fit`, `fdescribe`, `xit`, `xtest`, `xdescribe`.
|
||||
|
||||
This rule enforces usages from the **only & skip** list.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if you use one of the keywords from the **'f' &
|
||||
'x'** list to focus/skip a test.
|
||||
|
||||
```js
|
||||
/*eslint jest/no-test-prefixes: "error"*/
|
||||
|
||||
it.only('foo'); // valid
|
||||
test.only('foo'); // valid
|
||||
describe.only('foo'); // valid
|
||||
it.skip('foo'); // valid
|
||||
test.skip('foo'); // valid
|
||||
describe.skip('foo'); // valid
|
||||
|
||||
fit('foo'); // invalid
|
||||
fdescribe('foo'); // invalid
|
||||
xit('foo'); // invalid
|
||||
xtest('foo'); // invalid
|
||||
xdescribe('foo'); // invalid
|
||||
```
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Disallow explicitly returning from tests (`no-test-return-statement`)
|
||||
|
||||
Tests in Jest should be void and not return values.
|
||||
|
||||
If you are returning Promises then you should update the test to use
|
||||
`async/await`.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if you use a return statement inside a test body.
|
||||
|
||||
```js
|
||||
/*eslint jest/no-test-return-statement: "error"*/
|
||||
|
||||
// valid:
|
||||
|
||||
it('noop', function () {});
|
||||
|
||||
test('noop', () => {});
|
||||
|
||||
test('one arrow', () => expect(1).toBe(1));
|
||||
|
||||
test('empty');
|
||||
|
||||
test('one', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
|
||||
it('one', function () {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
|
||||
it('returning a promise', async () => {
|
||||
await new Promise(res => setTimeout(res, 100));
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
|
||||
// invalid:
|
||||
test('return an expect', () => {
|
||||
return expect(1).toBe(1);
|
||||
});
|
||||
|
||||
it('returning a promise', function () {
|
||||
return new Promise(res => setTimeout(res, 100)).then(() => expect(1).toBe(1));
|
||||
});
|
||||
```
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Suggest using `toBeCalledWith()` or `toHaveBeenCalledWith()` (`prefer-called-with`)
|
||||
|
||||
The `toBeCalled()` matcher is used to assert that a mock function has been
|
||||
called one or more times, without checking the arguments passed. The assertion
|
||||
is stronger when arguments are also validated using the `toBeCalledWith()`
|
||||
matcher. When some arguments are difficult to check, using generic match like
|
||||
`expect.anything()` at least enforces number and position of arguments.
|
||||
|
||||
This rule warns if the form without argument checking is used, except for `.not`
|
||||
enforcing a function has never been called.
|
||||
|
||||
## Rule details
|
||||
|
||||
The following patterns are warnings:
|
||||
|
||||
```js
|
||||
expect(someFunction).toBeCalled();
|
||||
|
||||
expect(someFunction).toHaveBeenCalled();
|
||||
```
|
||||
|
||||
The following patterns are not warnings:
|
||||
|
||||
```js
|
||||
expect(noArgsFunction).toBeCalledWith();
|
||||
|
||||
expect(roughArgsFunction).toBeCalledWith(expect.anything(), expect.any(Date));
|
||||
|
||||
expect(anyArgsFunction).toBeCalledTimes(1);
|
||||
|
||||
expect(uncalledFunction).not.toBeCalled();
|
||||
```
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# Suggest using the built-in comparison matchers (`prefer-comparison-matcher`)
|
||||
|
||||
Jest has a number of built-in matchers for comparing numbers, which allow for
|
||||
more readable tests and error messages if an expectation fails.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule checks for comparisons in tests that could be replaced with one of the
|
||||
following built-in comparison matchers:
|
||||
|
||||
- `toBeGreaterThan`
|
||||
- `toBeGreaterThanOrEqual`
|
||||
- `toBeLessThan`
|
||||
- `toBeLessThanOrEqual`
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
expect(x > 5).toBe(true);
|
||||
expect(x < 7).not.toEqual(true);
|
||||
expect(x <= y).toStrictEqual(true);
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
expect(x).toBeGreaterThan(5);
|
||||
expect(x).not.toBeLessThanOrEqual(7);
|
||||
expect(x).toBeLessThanOrEqual(y);
|
||||
|
||||
// special case - see below
|
||||
expect(x < 'Carl').toBe(true);
|
||||
```
|
||||
|
||||
Note that these matchers only work with numbers and bigints, and that the rule
|
||||
assumes that any variables on either side of the comparison operator are of one
|
||||
of those types - this means if you're using the comparison operator with
|
||||
strings, the fix applied by this rule will result in an error.
|
||||
|
||||
```js
|
||||
expect(myName).toBeGreaterThanOrEqual(theirName); // Matcher error: received value must be a number or bigint
|
||||
```
|
||||
|
||||
The reason for this is that comparing strings with these operators is expected
|
||||
to be very rare and would mean not being able to have an automatic fixer for
|
||||
this rule.
|
||||
|
||||
If for some reason you are using these operators to compare strings, you can
|
||||
disable this rule using an inline
|
||||
[configuration comment](https://eslint.org/docs/user-guide/configuring/rules#disabling-rules):
|
||||
|
||||
```js
|
||||
// eslint-disable-next-line jest/prefer-comparison-matcher
|
||||
expect(myName > theirName).toBe(true);
|
||||
```
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# Suggest using the built-in equality matchers (`prefer-equality-matcher`)
|
||||
|
||||
Jest has built-in matchers for expecting equality, which allow for more readable
|
||||
tests and error messages if an expectation fails.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule checks for _strict_ equality checks (`===` & `!==`) in tests that
|
||||
could be replaced with one of the following built-in equality matchers:
|
||||
|
||||
- `toBe`
|
||||
- `toEqual`
|
||||
- `toStrictEqual`
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
expect(x === 5).toBe(true);
|
||||
expect(name === 'Carl').not.toEqual(true);
|
||||
expect(myObj !== thatObj).toStrictEqual(true);
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
expect(x).toBe(5);
|
||||
expect(name).not.toEqual('Carl');
|
||||
expect(myObj).toStrictEqual(thatObj);
|
||||
```
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
# Suggest using `expect.assertions()` OR `expect.hasAssertions()` (`prefer-expect-assertions`)
|
||||
|
||||
Ensure every test to have either `expect.assertions(<number of assertions>)` OR
|
||||
`expect.hasAssertions()` as its first expression.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if,
|
||||
|
||||
- `expect.assertions(<number of assertions>)` OR `expect.hasAssertions()` is not
|
||||
present as first statement in a test, e.g.:
|
||||
|
||||
```js
|
||||
test('my test', () => {
|
||||
expect(someThing()).toEqual('foo');
|
||||
});
|
||||
```
|
||||
|
||||
- `expect.assertions(<number of assertions>)` is the first statement in a test
|
||||
where argument passed to `expect.assertions(<number of assertions>)` is not a
|
||||
valid number, e.g.:
|
||||
|
||||
```js
|
||||
test('my test', () => {
|
||||
expect.assertions('1');
|
||||
expect(someThing()).toEqual('foo');
|
||||
});
|
||||
```
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
test('my test', () => {
|
||||
expect.assertions('1');
|
||||
expect(someThing()).toEqual('foo');
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
expect(someThing()).toEqual('foo');
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
test('my test', () => {
|
||||
expect.assertions(1);
|
||||
expect(someThing()).toEqual('foo');
|
||||
});
|
||||
|
||||
test('my test', () => {
|
||||
expect.hasAssertions();
|
||||
expect(someThing()).toEqual('foo');
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
This rule can be configured to only check tests that match certain patterns that
|
||||
typically look like `expect` calls might be missed, such as in promises or
|
||||
loops.
|
||||
|
||||
By default, none of these options are enabled meaning the rule checks _every_
|
||||
test for a call to either `expect.hasAssertions` or `expect.assertions`. If any
|
||||
of the options are enabled the rule checks any test that matches _at least one_
|
||||
of the patterns represented by the enabled options (think "OR" rather than
|
||||
"AND").
|
||||
|
||||
#### `onlyFunctionsWithAsyncKeyword`
|
||||
|
||||
When `true`, this rule will only warn for tests that use the `async` keyword.
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"jest/prefer-expect-assertions": [
|
||||
"warn",
|
||||
{ "onlyFunctionsWithAsyncKeyword": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When `onlyFunctionsWithAsyncKeyword` option is set to `true`, the following
|
||||
pattern would be a warning:
|
||||
|
||||
```js
|
||||
test('my test', async () => {
|
||||
const result = await someAsyncFunc();
|
||||
expect(result).toBe('foo');
|
||||
});
|
||||
```
|
||||
|
||||
While the following patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
test('my test', () => {
|
||||
const result = someFunction();
|
||||
expect(result).toBe('foo');
|
||||
});
|
||||
|
||||
test('my test', async () => {
|
||||
expect.assertions(1);
|
||||
const result = await someAsyncFunc();
|
||||
expect(result).toBe('foo');
|
||||
});
|
||||
```
|
||||
|
||||
#### `onlyFunctionsWithExpectInLoop`
|
||||
|
||||
When `true`, this rule will only warn for tests that have `expect` calls within
|
||||
a native loop.
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"jest/prefer-expect-assertions": [
|
||||
"warn",
|
||||
{ "onlyFunctionsWithExpectInLoop": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Examples of **incorrect** code when `'onlyFunctionsWithExpectInLoop'` is `true`:
|
||||
|
||||
```js
|
||||
describe('getNumbers', () => {
|
||||
it('only returns numbers that are greater than zero', () => {
|
||||
const numbers = getNumbers();
|
||||
|
||||
for (const number in numbers) {
|
||||
expect(number).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code when `'onlyFunctionsWithExpectInLoop'` is `true`:
|
||||
|
||||
```js
|
||||
describe('getNumbers', () => {
|
||||
it('only returns numbers that are greater than zero', () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
const numbers = getNumbers();
|
||||
|
||||
for (const number in numbers) {
|
||||
expect(number).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns more than one number', () => {
|
||||
expect(getNumbers().length).toBeGreaterThan(1);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### `onlyFunctionsWithExpectInCallback`
|
||||
|
||||
When `true`, this rule will only warn for tests that have `expect` calls within
|
||||
a callback.
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"jest/prefer-expect-assertions": [
|
||||
"warn",
|
||||
{ "onlyFunctionsWithExpectInCallback": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Examples of **incorrect** code when `'onlyFunctionsWithExpectInCallback'` is
|
||||
`true`:
|
||||
|
||||
```js
|
||||
describe('getNumbers', () => {
|
||||
it('only returns numbers that are greater than zero', () => {
|
||||
const numbers = getNumbers();
|
||||
|
||||
getNumbers().forEach(number => {
|
||||
expect(number).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/users', () => {
|
||||
it.each([1, 2, 3])('returns ok', id => {
|
||||
client.get(`/users/${id}`, response => {
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code when `'onlyFunctionsWithExpectInCallback'` is
|
||||
`true`:
|
||||
|
||||
```js
|
||||
describe('getNumbers', () => {
|
||||
it('only returns numbers that are greater than zero', () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
const numbers = getNumbers();
|
||||
|
||||
getNumbers().forEach(number => {
|
||||
expect(number).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/users', () => {
|
||||
it.each([1, 2, 3])('returns ok', id => {
|
||||
expect.assertions(1);
|
||||
|
||||
client.get(`/users/${id}`, response => {
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# Prefer `await expect(...).resolves` over `expect(await ...)` syntax (`prefer-expect-resolves`)
|
||||
|
||||
When working with promises, there are two primary ways you can test the resolved
|
||||
value:
|
||||
|
||||
1. use the `resolve` modifier on `expect`
|
||||
(`await expect(...).resolves.<matcher>` style)
|
||||
2. `await` the promise and assert against its result
|
||||
(`expect(await ...).<matcher>` style)
|
||||
|
||||
While the second style is arguably less dependent on `jest`, if the promise
|
||||
rejects it will be treated as a general error, resulting in less predictable
|
||||
behaviour and output from `jest`.
|
||||
|
||||
Additionally, favoring the first style ensures consistency with its `rejects`
|
||||
counterpart, as there is no way of "awaiting" a rejection.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if an `await` is done within an `expect`, and
|
||||
recommends using `resolves` instead.
|
||||
|
||||
Examples of **incorrect** code for this rule
|
||||
|
||||
```js
|
||||
it('passes', async () => {
|
||||
expect(await someValue()).toBe(true);
|
||||
});
|
||||
|
||||
it('is true', async () => {
|
||||
const myPromise = Promise.resolve(true);
|
||||
|
||||
expect(await myPromise).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule
|
||||
|
||||
```js
|
||||
it('passes', async () => {
|
||||
await expect(someValue()).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('is true', async () => {
|
||||
const myPromise = Promise.resolve(true);
|
||||
|
||||
await expect(myPromise).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('errors', async () => {
|
||||
await expect(Promise.rejects('oh noes!')).rejects.toThrow('oh noes!');
|
||||
});
|
||||
```
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# Prefer having hooks in a consistent order (`prefer-hooks-in-order`)
|
||||
|
||||
While hooks can be setup in any order, they're always called by `jest` in this
|
||||
specific order:
|
||||
|
||||
1. `beforeAll`
|
||||
1. `beforeEach`
|
||||
1. `afterEach`
|
||||
1. `afterAll`
|
||||
|
||||
This rule aims to make that more obvious by enforcing grouped hooks be setup in
|
||||
that order within tests.
|
||||
|
||||
## Rule Details
|
||||
|
||||
Examples of **incorrect** code for this rule
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-hooks-in-order: "error" */
|
||||
|
||||
describe('foo', () => {
|
||||
beforeEach(() => {
|
||||
seedMyDatabase();
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
createMyDatabase();
|
||||
});
|
||||
|
||||
it('accepts this input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('returns that value', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
describe('when the database has specific values', () => {
|
||||
const specificValue = '...';
|
||||
|
||||
beforeEach(() => {
|
||||
seedMyDatabase(specificValue);
|
||||
});
|
||||
|
||||
it('accepts that input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('throws an error', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearLogger();
|
||||
});
|
||||
beforeEach(() => {
|
||||
mockLogger();
|
||||
});
|
||||
|
||||
it('logs a message', () => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
removeMyDatabase();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-hooks-in-order: "error" */
|
||||
|
||||
describe('foo', () => {
|
||||
beforeAll(() => {
|
||||
createMyDatabase();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
seedMyDatabase();
|
||||
});
|
||||
|
||||
it('accepts this input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('returns that value', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
describe('when the database has specific values', () => {
|
||||
const specificValue = '...';
|
||||
|
||||
beforeEach(() => {
|
||||
seedMyDatabase(specificValue);
|
||||
});
|
||||
|
||||
it('accepts that input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('throws an error', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockLogger();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearLogger();
|
||||
});
|
||||
|
||||
it('logs a message', () => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
removeMyDatabase();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Also See
|
||||
|
||||
- [`prefer-hooks-on-top`](prefer-hooks-on-top.md)
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Order of Execution](https://jestjs.io/docs/setup-teardown#order-of-execution)
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
# Suggest having hooks before any test cases (`prefer-hooks-on-top`)
|
||||
|
||||
While hooks can be setup anywhere in a test file, they are always called in a
|
||||
specific order, which means it can be confusing if they're intermixed with test
|
||||
cases.
|
||||
|
||||
This rule helps to ensure that hooks are always defined before test cases.
|
||||
|
||||
## Rule Details
|
||||
|
||||
Examples of **incorrect** code for this rule
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-hooks-on-top: "error" */
|
||||
|
||||
describe('foo', () => {
|
||||
beforeEach(() => {
|
||||
seedMyDatabase();
|
||||
});
|
||||
|
||||
it('accepts this input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
createMyDatabase();
|
||||
});
|
||||
|
||||
it('returns that value', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
describe('when the database has specific values', () => {
|
||||
const specificValue = '...';
|
||||
|
||||
beforeEach(() => {
|
||||
seedMyDatabase(specificValue);
|
||||
});
|
||||
|
||||
it('accepts that input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('throws an error', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearLogger();
|
||||
});
|
||||
beforeEach(() => {
|
||||
mockLogger();
|
||||
});
|
||||
|
||||
it('logs a message', () => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
removeMyDatabase();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-hooks-on-top: "error" */
|
||||
|
||||
describe('foo', () => {
|
||||
beforeAll(() => {
|
||||
createMyDatabase();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
seedMyDatabase();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
clearMyDatabase();
|
||||
});
|
||||
|
||||
it('accepts this input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('returns that value', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
describe('when the database has specific values', () => {
|
||||
const specificValue = '...';
|
||||
|
||||
beforeEach(() => {
|
||||
seedMyDatabase(specificValue);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockLogger();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearLogger();
|
||||
});
|
||||
|
||||
it('accepts that input', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('throws an error', () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
it('logs a message', () => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
# Enforce lowercase test names (`prefer-lowercase-title`)
|
||||
|
||||
## Rule details
|
||||
|
||||
Enforce `it`, `test` and `describe` to have descriptions that begin with a
|
||||
lowercase letter. This provides more readable test failures. This rule is not
|
||||
enabled by default.
|
||||
|
||||
The following pattern is considered a warning:
|
||||
|
||||
```js
|
||||
it('Adds 1 + 2 to equal 3', () => {
|
||||
expect(sum(1, 2)).toBe(3);
|
||||
});
|
||||
```
|
||||
|
||||
The following pattern is not considered a warning:
|
||||
|
||||
```js
|
||||
it('adds 1 + 2 to equal 3', () => {
|
||||
expect(sum(1, 2)).toBe(3);
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/prefer-lowercase-title": [
|
||||
"error",
|
||||
{
|
||||
"ignore": ["describe", "test"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `ignore`
|
||||
|
||||
This array option controls which Jest functions are checked by this rule. There
|
||||
are three possible values:
|
||||
|
||||
- `"describe"`
|
||||
- `"test"`
|
||||
- `"it"`
|
||||
|
||||
By default, none of these options are enabled (the equivalent of
|
||||
`{ "ignore": [] }`).
|
||||
|
||||
Example of **correct** code for the `{ "ignore": ["describe"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["describe"] }] */
|
||||
|
||||
describe('Uppercase description');
|
||||
```
|
||||
|
||||
Example of **correct** code for the `{ "ignore": ["test"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["test"] }] */
|
||||
|
||||
test('Uppercase description');
|
||||
```
|
||||
|
||||
Example of **correct** code for the `{ "ignore": ["it"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-lowercase-title: ["error", { "ignore": ["it"] }] */
|
||||
|
||||
it('Uppercase description');
|
||||
```
|
||||
|
||||
### `allowedPrefixes`
|
||||
|
||||
This array option allows specifying prefixes, which contain capitals that titles
|
||||
can start with. This can be useful when writing tests for API endpoints, where
|
||||
you'd like to prefix with the HTTP method.
|
||||
|
||||
By default, nothing is allowed (the equivalent of `{ "allowedPrefixes": [] }`).
|
||||
|
||||
Example of **correct** code for the `{ "allowedPrefixes": ["GET"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-lowercase-title: ["error", { "allowedPrefixes": ["GET"] }] */
|
||||
|
||||
describe('GET /live');
|
||||
```
|
||||
|
||||
### `ignoreTopLevelDescribe`
|
||||
|
||||
This option can be set to allow only the top-level `describe` blocks to have a
|
||||
title starting with an upper-case letter.
|
||||
|
||||
Example of **correct** code for the `{ "ignoreTopLevelDescribe": true }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/prefer-lowercase-title: ["error", { "ignoreTopLevelDescribe": true }] */
|
||||
describe('MyClass', () => {
|
||||
describe('#myMethod', () => {
|
||||
it('does things', () => {
|
||||
//
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Prefer mock resolved/rejected shorthands for promises (`prefer-mock-promise-shorthand`)
|
||||
|
||||
When working with mocks of functions that return promises, Jest provides some
|
||||
API sugar functions to reduce the amount of boilerplate you have to write.
|
||||
|
||||
These methods should be preferred when possible.
|
||||
|
||||
## Rule Details
|
||||
|
||||
The following patterns are warnings:
|
||||
|
||||
```js
|
||||
jest.fn().mockImplementation(() => Promise.resolve(123));
|
||||
jest
|
||||
.spyOn(fs.promises, 'readFile')
|
||||
.mockReturnValue(Promise.reject(new Error('oh noes!')));
|
||||
|
||||
myFunction
|
||||
.mockReturnValueOnce(Promise.resolve(42))
|
||||
.mockImplementationOnce(() => Promise.resolve(42))
|
||||
.mockReturnValue(Promise.reject(new Error('too many calls!')));
|
||||
```
|
||||
|
||||
The following patterns are not warnings:
|
||||
|
||||
```js
|
||||
jest.fn().mockResolvedValue(123);
|
||||
jest.spyOn(fs.promises, 'readFile').mockRejectedValue(new Error('oh noes!'));
|
||||
|
||||
myFunction
|
||||
.mockResolvedValueOnce(42)
|
||||
.mockResolvedValueOnce(42)
|
||||
.mockRejectedValue(new Error('too many calls!'));
|
||||
```
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
# Prefer including a hint with external snapshots (`prefer-snapshot-hint`)
|
||||
|
||||
When working with external snapshot matchers it's considered best practice to
|
||||
provide a hint (as the last argument to the matcher) describing the expected
|
||||
snapshot content that will be included in the snapshots name by Jest.
|
||||
|
||||
This makes it easier for reviewers to verify the snapshots during review, and
|
||||
for anyone to know whether an outdated snapshot is the correct behavior before
|
||||
updating.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule looks for any use of an external snapshot matcher (e.g.
|
||||
`toMatchSnapshot` and `toThrowErrorMatchingSnapshot`) and checks if they include
|
||||
a snapshot hint.
|
||||
|
||||
## Options
|
||||
|
||||
### `'always'`
|
||||
|
||||
Require a hint to _always_ be provided when using external snapshot matchers.
|
||||
|
||||
Examples of **incorrect** code for the `'always'` option:
|
||||
|
||||
```js
|
||||
const snapshotOutput = ({ stdout, stderr }) => {
|
||||
expect(stdout).toMatchSnapshot();
|
||||
expect(stderr).toMatchSnapshot();
|
||||
};
|
||||
|
||||
describe('cli', () => {
|
||||
describe('--version flag', () => {
|
||||
it('prints the version', async () => {
|
||||
snapshotOutput(await runCli(['--version']));
|
||||
});
|
||||
});
|
||||
|
||||
describe('--config flag', () => {
|
||||
it('reads the config', async () => {
|
||||
const { stdout, parsedConfig } = await runCli([
|
||||
'--config',
|
||||
'jest.config.js',
|
||||
]);
|
||||
|
||||
expect(stdout).toMatchSnapshot();
|
||||
expect(parsedConfig).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('prints nothing to stderr', async () => {
|
||||
const { stderr } = await runCli(['--config', 'jest.config.js']);
|
||||
|
||||
expect(stderr).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('when the file does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
runCli(['--config', 'does-not-exist.js']),
|
||||
).rejects.toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for the `'always'` option:
|
||||
|
||||
```js
|
||||
const snapshotOutput = ({ stdout, stderr }, hints) => {
|
||||
expect(stdout).toMatchSnapshot({}, `stdout: ${hints.stdout}`);
|
||||
expect(stderr).toMatchSnapshot({}, `stderr: ${hints.stderr}`);
|
||||
};
|
||||
|
||||
describe('cli', () => {
|
||||
describe('--version flag', () => {
|
||||
it('prints the version', async () => {
|
||||
snapshotOutput(await runCli(['--version']), {
|
||||
stdout: 'version string',
|
||||
stderr: 'empty',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--config flag', () => {
|
||||
it('reads the config', async () => {
|
||||
const { stdout } = await runCli(['--config', 'jest.config.js']);
|
||||
|
||||
expect(stdout).toMatchSnapshot({}, 'stdout: config settings');
|
||||
});
|
||||
|
||||
it('prints nothing to stderr', async () => {
|
||||
const { stderr } = await runCli(['--config', 'jest.config.js']);
|
||||
|
||||
expect(stderr).toMatchInlineSnapshot();
|
||||
});
|
||||
|
||||
describe('when the file does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
runCli(['--config', 'does-not-exist.js']),
|
||||
).rejects.toThrowErrorMatchingSnapshot('stderr: config error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### `'multi'` (default)
|
||||
|
||||
Require a hint to be provided when there are multiple external snapshot matchers
|
||||
within the scope (meaning it includes nested calls).
|
||||
|
||||
Examples of **incorrect** code for the `'multi'` option:
|
||||
|
||||
```js
|
||||
const snapshotOutput = ({ stdout, stderr }) => {
|
||||
expect(stdout).toMatchSnapshot();
|
||||
expect(stderr).toMatchSnapshot();
|
||||
};
|
||||
|
||||
describe('cli', () => {
|
||||
describe('--version flag', () => {
|
||||
it('prints the version', async () => {
|
||||
snapshotOutput(await runCli(['--version']));
|
||||
});
|
||||
});
|
||||
|
||||
describe('--config flag', () => {
|
||||
it('reads the config', async () => {
|
||||
const { stdout, parsedConfig } = await runCli([
|
||||
'--config',
|
||||
'jest.config.js',
|
||||
]);
|
||||
|
||||
expect(stdout).toMatchSnapshot();
|
||||
expect(parsedConfig).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('prints nothing to stderr', async () => {
|
||||
const { stderr } = await runCli(['--config', 'jest.config.js']);
|
||||
|
||||
expect(stderr).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for the `'multi'` option:
|
||||
|
||||
```js
|
||||
const snapshotOutput = ({ stdout, stderr }, hints) => {
|
||||
expect(stdout).toMatchSnapshot({}, `stdout: ${hints.stdout}`);
|
||||
expect(stderr).toMatchSnapshot({}, `stderr: ${hints.stderr}`);
|
||||
};
|
||||
|
||||
describe('cli', () => {
|
||||
describe('--version flag', () => {
|
||||
it('prints the version', async () => {
|
||||
snapshotOutput(await runCli(['--version']), {
|
||||
stdout: 'version string',
|
||||
stderr: 'empty',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--config flag', () => {
|
||||
it('reads the config', async () => {
|
||||
const { stdout } = await runCli(['--config', 'jest.config.js']);
|
||||
|
||||
expect(stdout).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('prints nothing to stderr', async () => {
|
||||
const { stderr } = await runCli(['--config', 'jest.config.js']);
|
||||
|
||||
expect(stderr).toMatchInlineSnapshot();
|
||||
});
|
||||
|
||||
describe('when the file does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(
|
||||
runCli(['--config', 'does-not-exist.js']),
|
||||
).rejects.toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Suggest using `jest.spyOn()` (`prefer-spy-on`)
|
||||
|
||||
When mocking a function by overwriting a property you have to manually restore
|
||||
the original implementation when cleaning up. When using `jest.spyOn()` Jest
|
||||
keeps track of changes, and they can be restored with `jest.restoreAllMocks()`,
|
||||
`mockFn.mockRestore()` or by setting `restoreMocks` to `true` in the Jest
|
||||
config.
|
||||
|
||||
Note: The mock created by `jest.spyOn()` still behaves the same as the original
|
||||
function. The original function can be overwritten with
|
||||
`mockFn.mockImplementation()` or by some of the
|
||||
[other mock functions](https://jestjs.io/docs/en/mock-function-api).
|
||||
|
||||
```js
|
||||
Date.now = jest.fn(); // Original behaviour lost, returns undefined
|
||||
|
||||
jest.spyOn(Date, 'now'); // Turned into a mock function but behaviour hasn't changed
|
||||
jest.spyOn(Date, 'now').mockImplementation(() => 10); // Will always return 10
|
||||
jest.spyOn(Date, 'now').mockReturnValue(10); // Will always return 10
|
||||
```
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if an object's property is overwritten with a jest
|
||||
mock.
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
Date.now = jest.fn();
|
||||
Date.now = jest.fn(() => 10);
|
||||
```
|
||||
|
||||
These patterns would not be considered warnings:
|
||||
|
||||
```js
|
||||
jest.spyOn(Date, 'now');
|
||||
jest.spyOn(Date, 'now').mockImplementation(() => 10);
|
||||
```
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Suggest using `toStrictEqual()` (`prefer-strict-equal`)
|
||||
|
||||
`toStrictEqual` not only checks that two objects contain the same data but also
|
||||
that they have the same structure. It is common to expect objects to not only
|
||||
have identical values but also to have identical keys. A stricter equality will
|
||||
catch cases where two objects do not have identical keys.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if `toEqual()` is used to assert equality.
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following pattern is considered warning:
|
||||
|
||||
```js
|
||||
expect({ a: 'a', b: undefined }).toEqual({ a: 'a' }); // true
|
||||
```
|
||||
|
||||
The following pattern is not warning:
|
||||
|
||||
```js
|
||||
expect({ a: 'a', b: undefined }).toStrictEqual({ a: 'a' }); // false
|
||||
```
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# Suggest using `toBe()` for primitive literals (`prefer-to-be`)
|
||||
|
||||
When asserting against primitive literals such as numbers and strings, the
|
||||
equality matchers all operate the same, but read slightly differently in code.
|
||||
|
||||
This rule recommends using the `toBe` matcher in these situations, as it forms
|
||||
the most grammatically natural sentence. For `null`, `undefined`, and `NaN` this
|
||||
rule recommends using their specific `toBe` matchers, as they give better error
|
||||
messages as well.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if `toEqual()` or `toStrictEqual()` are used to
|
||||
assert a primitive literal value such as numbers, strings, and booleans.
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
expect(value).not.toEqual(5);
|
||||
expect(getMessage()).toStrictEqual('hello world');
|
||||
expect(loadMessage()).resolves.toEqual('hello world');
|
||||
```
|
||||
|
||||
The following pattern is not warning:
|
||||
|
||||
```js
|
||||
expect(value).not.toBe(5);
|
||||
expect(getMessage()).toBe('hello world');
|
||||
expect(loadMessage()).resolves.toBe('hello world');
|
||||
expect(didError).not.toBe(true);
|
||||
|
||||
expect(catchError()).toStrictEqual({ message: 'oh noes!' });
|
||||
```
|
||||
|
||||
For `null`, `undefined`, and `NaN`, this rule triggers a warning if `toBe` is
|
||||
used to assert against those literal values instead of their more specific
|
||||
`toBe` counterparts:
|
||||
|
||||
```js
|
||||
expect(value).not.toBe(undefined);
|
||||
expect(getMessage()).toBe(null);
|
||||
expect(countMessages()).resolves.not.toBe(NaN);
|
||||
```
|
||||
|
||||
The following pattern is not warning:
|
||||
|
||||
```js
|
||||
expect(value).toBeDefined();
|
||||
expect(getMessage()).toBeNull();
|
||||
expect(countMessages()).resolves.not.toBeNaN();
|
||||
|
||||
expect(catchError()).toStrictEqual({ message: undefined });
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Suggest using `toContain()` (`prefer-to-contain`)
|
||||
|
||||
In order to have a better failure message, `toContain()` should be used upon
|
||||
asserting expectations on an array containing an object.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if `toBe()`, `toEqual()` or `toStrictEqual()` is
|
||||
used to assert object inclusion in an array
|
||||
|
||||
```js
|
||||
expect(a.includes(b)).toBe(true);
|
||||
```
|
||||
|
||||
```js
|
||||
expect(a.includes(b)).not.toBe(true);
|
||||
```
|
||||
|
||||
```js
|
||||
expect(a.includes(b)).toBe(false);
|
||||
```
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
expect(a.includes(b)).toBe(true);
|
||||
|
||||
expect(a.includes(b)).not.toBe(true);
|
||||
|
||||
expect(a.includes(b)).toBe(false);
|
||||
|
||||
expect(a.includes(b)).toEqual(true);
|
||||
|
||||
expect(a.includes(b)).toStrictEqual(true);
|
||||
```
|
||||
|
||||
The following patterns are not considered warnings:
|
||||
|
||||
```js
|
||||
expect(a).toContain(b);
|
||||
|
||||
expect(a).not.toContain(b);
|
||||
```
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Suggest using `toHaveLength()` (`prefer-to-have-length`)
|
||||
|
||||
In order to have a better failure message, `toHaveLength()` should be used upon
|
||||
asserting expectations on objects length property.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if `toBe()`, `toEqual()` or `toStrictEqual()` is
|
||||
used to assert objects length property.
|
||||
|
||||
```js
|
||||
expect(files.length).toBe(1);
|
||||
```
|
||||
|
||||
This rule is enabled by default.
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
expect(files.length).toBe(1);
|
||||
|
||||
expect(files.length).toEqual(1);
|
||||
|
||||
expect(files.length).toStrictEqual(1);
|
||||
```
|
||||
|
||||
The following pattern is not warning:
|
||||
|
||||
```js
|
||||
expect(files).toHaveLength(1);
|
||||
```
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Suggest using `test.todo` (`prefer-todo`)
|
||||
|
||||
When test cases are empty then it is better to mark them as `test.todo` as it
|
||||
will be highlighted in the summary output.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if empty test cases are used without 'test.todo'.
|
||||
|
||||
```js
|
||||
test('i need to write this test');
|
||||
```
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following pattern is considered warning:
|
||||
|
||||
```js
|
||||
test('i need to write this test'); // Unimplemented test case
|
||||
test('i need to write this test', () => {}); // Empty test case body
|
||||
test.skip('i need to write this test', () => {}); // Empty test case body
|
||||
```
|
||||
|
||||
The following pattern is not warning:
|
||||
|
||||
```js
|
||||
test.todo('i need to write this test');
|
||||
```
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
# Require setup and teardown code to be within a hook (`require-hook`)
|
||||
|
||||
Often while writing tests you have some setup work that needs to happen before
|
||||
tests run, and you have some finishing work that needs to happen after tests
|
||||
run. Jest provides helper functions to handle this.
|
||||
|
||||
It's common when writing tests to need to perform setup work that needs to
|
||||
happen before tests run, and finishing work after tests run.
|
||||
|
||||
Because Jest executes all `describe` handlers in a test file _before_ it
|
||||
executes any of the actual tests, it's important to ensure setup and teardown
|
||||
work is done inside `before*` and `after*` handlers respectively, rather than
|
||||
inside the `describe` blocks.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule flags any expression that is either at the toplevel of a test file or
|
||||
directly within the body of a `describe`, _except_ for the following:
|
||||
|
||||
- `import` statements
|
||||
- `const` variables
|
||||
- `let` _declarations_, and initializations to `null` or `undefined`
|
||||
- Classes
|
||||
- Types
|
||||
- Calls to the standard Jest globals
|
||||
|
||||
This rule flags any function calls within test files that are directly within
|
||||
the body of a `describe`, and suggests wrapping them in one of the four
|
||||
lifecycle hooks.
|
||||
|
||||
Here is a slightly contrived test file showcasing some common cases that would
|
||||
be flagged:
|
||||
|
||||
```js
|
||||
import { database, isCity } from '../database';
|
||||
import { Logger } from '../../../src/Logger';
|
||||
import { loadCities } from '../api';
|
||||
|
||||
jest.mock('../api');
|
||||
|
||||
const initializeCityDatabase = () => {
|
||||
database.addCity('Vienna');
|
||||
database.addCity('San Juan');
|
||||
database.addCity('Wellington');
|
||||
};
|
||||
|
||||
const clearCityDatabase = () => {
|
||||
database.clear();
|
||||
};
|
||||
|
||||
initializeCityDatabase();
|
||||
|
||||
test('that persists cities', () => {
|
||||
expect(database.cities.length).toHaveLength(3);
|
||||
});
|
||||
|
||||
test('city database has Vienna', () => {
|
||||
expect(isCity('Vienna')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('city database has San Juan', () => {
|
||||
expect(isCity('San Juan')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when loading cities from the api', () => {
|
||||
let consoleWarnSpy = jest.spyOn(console, 'warn');
|
||||
|
||||
loadCities.mockResolvedValue(['Wellington', 'London']);
|
||||
|
||||
it('does not duplicate cities', async () => {
|
||||
await database.loadCities();
|
||||
|
||||
expect(database.cities).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('logs any duplicates', async () => {
|
||||
await database.loadCities();
|
||||
|
||||
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
||||
'Ignored duplicate cities: Wellington',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
clearCityDatabase();
|
||||
```
|
||||
|
||||
Here is the same slightly contrived test file showcasing the same common cases
|
||||
but in ways that would be **not** flagged:
|
||||
|
||||
```js
|
||||
import { database, isCity } from '../database';
|
||||
import { Logger } from '../../../src/Logger';
|
||||
import { loadCities } from '../api';
|
||||
|
||||
jest.mock('../api');
|
||||
|
||||
const initializeCityDatabase = () => {
|
||||
database.addCity('Vienna');
|
||||
database.addCity('San Juan');
|
||||
database.addCity('Wellington');
|
||||
};
|
||||
|
||||
const clearCityDatabase = () => {
|
||||
database.clear();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
initializeCityDatabase();
|
||||
});
|
||||
|
||||
test('that persists cities', () => {
|
||||
expect(database.cities.length).toHaveLength(3);
|
||||
});
|
||||
|
||||
test('city database has Vienna', () => {
|
||||
expect(isCity('Vienna')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('city database has San Juan', () => {
|
||||
expect(isCity('San Juan')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when loading cities from the api', () => {
|
||||
let consoleWarnSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleWarnSpy = jest.spyOn(console, 'warn');
|
||||
loadCities.mockResolvedValue(['Wellington', 'London']);
|
||||
});
|
||||
|
||||
it('does not duplicate cities', async () => {
|
||||
await database.loadCities();
|
||||
|
||||
expect(database.cities).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('logs any duplicates', async () => {
|
||||
await database.loadCities();
|
||||
|
||||
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
||||
'Ignored duplicate cities: Wellington',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearCityDatabase();
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
If there are methods that you want to call outside of hooks and tests, you can
|
||||
mark them as allowed using the `allowedFunctionCalls` option.
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/require-hook": [
|
||||
"error",
|
||||
{
|
||||
"allowedFunctionCalls": ["enableAutoDestroy"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Examples of **correct** code when using
|
||||
`{ "allowedFunctionCalls": ["enableAutoDestroy"] }` option:
|
||||
|
||||
```js
|
||||
/* eslint jest/require-hook: ["error", { "allowedFunctionCalls": ["enableAutoDestroy"] }] */
|
||||
|
||||
import { enableAutoDestroy, mount } from '@vue/test-utils';
|
||||
import { initDatabase, tearDownDatabase } from './databaseUtils';
|
||||
|
||||
enableAutoDestroy(afterEach);
|
||||
|
||||
beforeEach(initDatabase);
|
||||
afterEach(tearDownDatabase);
|
||||
|
||||
describe('Foo', () => {
|
||||
test('always returns 42', () => {
|
||||
expect(global.getAnswer()).toBe(42);
|
||||
});
|
||||
});
|
||||
```
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Require a message for `toThrow()` (`require-to-throw-message`)
|
||||
|
||||
`toThrow()` (and its alias `toThrowError()`) is used to check if an error is
|
||||
thrown by a function call, such as in `expect(() => a()).toThrow()`. However, if
|
||||
no message is defined, then the test will pass for any thrown error. Requiring a
|
||||
message ensures that the intended error is thrown.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if `toThrow()` or `toThrowError()` is used without
|
||||
an error message.
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
test('all the things', async () => {
|
||||
expect(() => a()).toThrow();
|
||||
|
||||
expect(() => a()).toThrowError();
|
||||
|
||||
await expect(a()).rejects.toThrow();
|
||||
|
||||
await expect(a()).rejects.toThrowError();
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns are not considered warnings:
|
||||
|
||||
```js
|
||||
test('all the things', async () => {
|
||||
expect(() => a()).toThrow('a');
|
||||
|
||||
expect(() => a()).toThrowError('a');
|
||||
|
||||
await expect(a()).rejects.toThrow('a');
|
||||
|
||||
await expect(a()).rejects.toThrowError('a');
|
||||
});
|
||||
```
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
# Require test cases and hooks to be inside a `describe` block (`require-top-level-describe`)
|
||||
|
||||
Jest allows you to organise your test files the way you want it. However, the
|
||||
more your codebase grows, the more it becomes hard to navigate in your test
|
||||
files. This rule makes sure you provide at least a top-level `describe` block in
|
||||
your test file.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule triggers a warning if a test case (`test` and `it`) or a hook
|
||||
(`beforeAll`, `beforeEach`, `afterEach`, `afterAll`) is not located in a
|
||||
top-level `describe` block.
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
// Above a describe block
|
||||
test('my test', () => {});
|
||||
describe('test suite', () => {
|
||||
it('test', () => {});
|
||||
});
|
||||
|
||||
// Below a describe block
|
||||
describe('test suite', () => {});
|
||||
test('my test', () => {});
|
||||
|
||||
// Same for hooks
|
||||
beforeAll('my beforeAll', () => {});
|
||||
describe('test suite', () => {});
|
||||
afterEach('my afterEach', () => {});
|
||||
```
|
||||
|
||||
The following patterns are **not** considered warnings:
|
||||
|
||||
```js
|
||||
// In a describe block
|
||||
describe('test suite', () => {
|
||||
test('my test', () => {});
|
||||
});
|
||||
|
||||
// In a nested describe block
|
||||
describe('test suite', () => {
|
||||
test('my test', () => {});
|
||||
describe('another test suite', () => {
|
||||
test('my other test', () => {});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
You can also enforce a limit on the number of describes allowed at the top-level
|
||||
using the `maxNumberOfTopLevelDescribes` option:
|
||||
|
||||
```json
|
||||
{
|
||||
"jest/require-top-level-describe": [
|
||||
"error",
|
||||
{
|
||||
"maxNumberOfTopLevelDescribes": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Examples of **incorrect** code with the above config:
|
||||
|
||||
```js
|
||||
describe('test suite', () => {
|
||||
it('test', () => {});
|
||||
});
|
||||
|
||||
describe('test suite', () => {});
|
||||
|
||||
describe('test suite', () => {});
|
||||
```
|
||||
|
||||
This option defaults to `Infinity`, allowing any number of top-level describes.
|
||||
|
||||
## When Not To Use It
|
||||
|
||||
Don't use this rule on non-jest test files.
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
# Enforce unbound methods are called with their expected scope (`unbound-method`)
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule extends the base [`@typescript-eslint/unbound-method`][original-rule]
|
||||
rule, meaning you must depend on `@typescript-eslint/eslint-plugin` for it to
|
||||
work. It adds support for understanding when it's ok to pass an unbound method
|
||||
to `expect` calls.
|
||||
|
||||
See the [`@typescript-eslint` documentation][original-rule] for more details on
|
||||
the `unbound-method` rule.
|
||||
|
||||
Note that while this rule requires type information to work, it will fail
|
||||
silently when not available allowing you to safely enable it on projects that
|
||||
are not using TypeScript.
|
||||
|
||||
## How to use
|
||||
|
||||
```json5
|
||||
{
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['test/**'],
|
||||
plugins: ['jest'],
|
||||
rules: {
|
||||
// you should turn the original rule off *only* for test files
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'jest/unbound-method': 'error',
|
||||
},
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/unbound-method': 'error',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
This rule should be applied to your test files in place of the original rule,
|
||||
which should be applied to the rest of your codebase.
|
||||
|
||||
## Options
|
||||
|
||||
See [`@typescript-eslint/unbound-method`][original-rule] options.
|
||||
|
||||
<sup>Taken with ❤️ [from `@typescript-eslint` core][original-rule]</sup>
|
||||
|
||||
[original-rule]:
|
||||
https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/unbound-method.md
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
# Enforce valid `describe()` callback (`valid-describe-callback`)
|
||||
|
||||
Using an improper `describe()` callback function can lead to unexpected test
|
||||
errors.
|
||||
|
||||
## Rule Details
|
||||
|
||||
This rule validates that the second parameter of a `describe()` function is a
|
||||
callback function. This callback function:
|
||||
|
||||
- should not be
|
||||
[async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)
|
||||
- should not contain any parameters
|
||||
- should not contain any `return` statements
|
||||
|
||||
The following `describe` function aliases are also validated:
|
||||
|
||||
- `describe`
|
||||
- `describe.only`
|
||||
- `describe.skip`
|
||||
- `fdescribe`
|
||||
- `xdescribe`
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
// Async callback functions are not allowed
|
||||
describe('myFunction()', async () => {
|
||||
// ...
|
||||
});
|
||||
|
||||
// Callback function parameters are not allowed
|
||||
describe('myFunction()', done => {
|
||||
// ...
|
||||
});
|
||||
|
||||
//
|
||||
describe('myFunction', () => {
|
||||
// No return statements are allowed in block of a callback function
|
||||
return Promise.resolve().then(() => {
|
||||
it('breaks', () => {
|
||||
throw new Error('Fail');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Returning a value from a describe block is not allowed
|
||||
describe('myFunction', () =>
|
||||
it('returns a truthy value', () => {
|
||||
expect(myFunction()).toBeTruthy();
|
||||
}));
|
||||
```
|
||||
|
||||
The following patterns are not considered warnings:
|
||||
|
||||
```js
|
||||
describe('myFunction()', () => {
|
||||
it('returns a truthy value', () => {
|
||||
expect(myFunction()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
```
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
# Ensure promises that have expectations in their chain are valid (`valid-expect-in-promise`)
|
||||
|
||||
Ensure promises that include expectations are returned or awaited.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule flags any promises within the body of a test that include expectations
|
||||
that have either not been returned or awaited.
|
||||
|
||||
The following patterns is considered warning:
|
||||
|
||||
```js
|
||||
it('promises a person', () => {
|
||||
api.getPersonByName('bob').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Bob');
|
||||
});
|
||||
});
|
||||
|
||||
it('promises a counted person', () => {
|
||||
const promise = api.getPersonByName('bob').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Bob');
|
||||
});
|
||||
|
||||
promise.then(() => {
|
||||
expect(analytics.gottenPeopleCount).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('promises multiple people', () => {
|
||||
const firstPromise = api.getPersonByName('bob').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Bob');
|
||||
});
|
||||
const secondPromise = api.getPersonByName('alice').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Alice');
|
||||
});
|
||||
|
||||
return Promise.any([firstPromise, secondPromise]);
|
||||
});
|
||||
```
|
||||
|
||||
The following pattern is not warning:
|
||||
|
||||
```js
|
||||
it('promises a person', async () => {
|
||||
await api.getPersonByName('bob').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Bob');
|
||||
});
|
||||
});
|
||||
|
||||
it('promises a counted person', () => {
|
||||
let promise = api.getPersonByName('bob').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Bob');
|
||||
});
|
||||
|
||||
promise = promise.then(() => {
|
||||
expect(analytics.gottenPeopleCount).toBe(1);
|
||||
});
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
it('promises multiple people', () => {
|
||||
const firstPromise = api.getPersonByName('bob').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Bob');
|
||||
});
|
||||
const secondPromise = api.getPersonByName('alice').then(person => {
|
||||
expect(person).toHaveProperty('name', 'Alice');
|
||||
});
|
||||
|
||||
return Promise.allSettled([firstPromise, secondPromise]);
|
||||
});
|
||||
```
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
# Enforce valid `expect()` usage (`valid-expect`)
|
||||
|
||||
Ensure `expect()` is called with a single argument and there is an actual
|
||||
expectation made.
|
||||
|
||||
## Rule details
|
||||
|
||||
This rule triggers a warning if `expect()` is called with more than one argument
|
||||
or without arguments. It would also issue a warning if there is nothing called
|
||||
on `expect()`, e.g.:
|
||||
|
||||
```js
|
||||
expect();
|
||||
expect('something');
|
||||
```
|
||||
|
||||
or when a matcher function was not called, e.g.:
|
||||
|
||||
```js
|
||||
expect(true).toBeDefined;
|
||||
```
|
||||
|
||||
or when an async assertion was not `await`ed or returned, e.g.:
|
||||
|
||||
```js
|
||||
expect(Promise.resolve('Hi!')).resolves.toBe('Hi!');
|
||||
```
|
||||
|
||||
This rule is enabled by default.
|
||||
|
||||
## Options
|
||||
|
||||
```json5
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
alwaysAwait: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
asyncMatchers: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
default: ['toResolve', 'toReject'],
|
||||
},
|
||||
minArgs: {
|
||||
type: 'number',
|
||||
minimum: 1,
|
||||
},
|
||||
maxArgs: {
|
||||
type: 'number',
|
||||
minimum: 1,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}
|
||||
```
|
||||
|
||||
### `alwaysAwait`
|
||||
|
||||
Enforces to use `await` inside block statements. Using `return` will trigger a
|
||||
warning. Returning one line statements with arrow functions is _always allowed_.
|
||||
|
||||
Examples of **incorrect** code for the { "alwaysAwait": **true** } option:
|
||||
|
||||
```js
|
||||
// alwaysAwait: true
|
||||
test('test1', async () => {
|
||||
await expect(Promise.resolve(2)).resolves.toBeDefined();
|
||||
return expect(Promise.resolve(1)).resolves.toBe(1); // `return` statement will trigger a warning
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for the { "alwaysAwait": **true** } option:
|
||||
|
||||
```js
|
||||
// alwaysAwait: true
|
||||
test('test1', async () => {
|
||||
await expect(Promise.resolve(2)).resolves.toBeDefined();
|
||||
await expect(Promise.resolve(1)).resolves.toBe(1);
|
||||
});
|
||||
|
||||
test('test2', () => expect(Promise.resolve(2)).resolves.toBe(2));
|
||||
```
|
||||
|
||||
### `asyncMatchers`
|
||||
|
||||
Allows specifying which matchers return promises, and so should be considered
|
||||
async when checking if an `expect` should be returned or awaited.
|
||||
|
||||
By default, this has a list of all the async matchers provided by
|
||||
`jest-extended` (namely, `toResolve` and `toReject`).
|
||||
|
||||
### `minArgs` & `maxArgs`
|
||||
|
||||
Enforces the minimum and maximum number of arguments that `expect` can take, and
|
||||
is required to take.
|
||||
|
||||
Both of these properties have a default value of `1`, which is the number of
|
||||
arguments supported by vanilla `expect`.
|
||||
|
||||
This is useful when you're using libraries that increase the number of arguments
|
||||
supported by `expect`, such as
|
||||
[`jest-expect-message`](https://www.npmjs.com/package/jest-expect-message).
|
||||
|
||||
### Default configuration
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
test('all the things', async () => {
|
||||
expect();
|
||||
expect().toEqual('something');
|
||||
expect('something', 'else');
|
||||
expect('something');
|
||||
await expect('something');
|
||||
expect(true).toBeDefined;
|
||||
expect(Promise.resolve('hello')).resolves;
|
||||
expect(Promise.resolve('hello')).resolves.toEqual('hello');
|
||||
Promise.resolve(expect(Promise.resolve('hello')).resolves.toEqual('hello'));
|
||||
Promise.all([
|
||||
expect(Promise.resolve('hello')).resolves.toEqual('hello'),
|
||||
expect(Promise.resolve('hi')).resolves.toEqual('hi'),
|
||||
]);
|
||||
});
|
||||
```
|
||||
|
||||
The following patterns are not warnings:
|
||||
|
||||
```js
|
||||
test('all the things', async () => {
|
||||
expect('something').toEqual('something');
|
||||
expect([1, 2, 3]).toEqual([1, 2, 3]);
|
||||
expect(true).toBeDefined();
|
||||
await expect(Promise.resolve('hello')).resolves.toEqual('hello');
|
||||
await Promise.resolve(
|
||||
expect(Promise.resolve('hello')).resolves.toEqual('hello'),
|
||||
);
|
||||
await Promise.all([
|
||||
expect(Promise.resolve('hello')).resolves.toEqual('hello'),
|
||||
expect(Promise.resolve('hi')).resolves.toEqual('hi'),
|
||||
]);
|
||||
});
|
||||
```
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
# Enforce valid titles (`valid-title`)
|
||||
|
||||
Checks that the title of Jest blocks are valid by ensuring that titles are:
|
||||
|
||||
- not empty,
|
||||
- is a string,
|
||||
- not prefixed with their block name,
|
||||
- have no leading or trailing spaces
|
||||
|
||||
## Rule Details
|
||||
|
||||
**emptyTitle**
|
||||
|
||||
An empty title is not informative, and serves little purpose.
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
describe('', () => {});
|
||||
describe('foo', () => {
|
||||
it('', () => {});
|
||||
});
|
||||
it('', () => {});
|
||||
test('', () => {});
|
||||
xdescribe('', () => {});
|
||||
xit('', () => {});
|
||||
xtest('', () => {});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
describe('foo', () => {});
|
||||
describe('foo', () => {
|
||||
it('bar', () => {});
|
||||
});
|
||||
test('foo', () => {});
|
||||
it('foo', () => {});
|
||||
xdescribe('foo', () => {});
|
||||
xit('foo', () => {});
|
||||
xtest('foo', () => {});
|
||||
```
|
||||
|
||||
**titleMustBeString**
|
||||
|
||||
Titles for test blocks should always be a string.
|
||||
|
||||
This is also applied to `describe` blocks by default, but can be turned off via
|
||||
the `ignoreTypeOfDescribeName` option:
|
||||
|
||||
Examples of **incorrect** code for this rule:
|
||||
|
||||
```js
|
||||
it(123, () => {});
|
||||
describe(String(/.+/), () => {});
|
||||
describe(myFunction, () => {});
|
||||
xdescribe(myFunction, () => {});
|
||||
describe(6, function () {});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule:
|
||||
|
||||
```js
|
||||
it('is a string', () => {});
|
||||
test('is a string', () => {});
|
||||
xtest('is a string', () => {});
|
||||
describe('is a string', () => {});
|
||||
describe.skip('is a string', () => {});
|
||||
fdescribe('is a string', () => {});
|
||||
```
|
||||
|
||||
Examples of **correct** code when `ignoreTypeOfDescribeName` is `true`:
|
||||
|
||||
```js
|
||||
it('is a string', () => {});
|
||||
test('is a string', () => {});
|
||||
xtest('is a string', () => {});
|
||||
describe('is a string', () => {});
|
||||
describe.skip('is a string', () => {});
|
||||
fdescribe('is a string', () => {});
|
||||
|
||||
describe(String(/.+/), () => {});
|
||||
describe(myFunction, () => {});
|
||||
xdescribe(myFunction, () => {});
|
||||
describe(6, function () {});
|
||||
```
|
||||
|
||||
**duplicatePrefix**
|
||||
|
||||
A `describe` / `test` block should not start with `duplicatePrefix`
|
||||
|
||||
Examples of **incorrect** code for this rule
|
||||
|
||||
```js
|
||||
test('test foo', () => {});
|
||||
it('it foo', () => {});
|
||||
|
||||
describe('foo', () => {
|
||||
test('test bar', () => {});
|
||||
});
|
||||
|
||||
describe('describe foo', () => {
|
||||
test('bar', () => {});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule
|
||||
|
||||
```js
|
||||
test('foo', () => {});
|
||||
it('foo', () => {});
|
||||
|
||||
describe('foo', () => {
|
||||
test('bar', () => {});
|
||||
});
|
||||
```
|
||||
|
||||
**accidentalSpace**
|
||||
|
||||
A `describe` / `test` block should not contain accidentalSpace
|
||||
|
||||
Examples of **incorrect** code for this rule
|
||||
|
||||
```js
|
||||
test(' foo', () => {});
|
||||
it(' foo', () => {});
|
||||
|
||||
describe('foo', () => {
|
||||
test(' bar', () => {});
|
||||
});
|
||||
|
||||
describe(' foo', () => {
|
||||
test('bar', () => {});
|
||||
});
|
||||
|
||||
describe('foo ', () => {
|
||||
test('bar', () => {});
|
||||
});
|
||||
```
|
||||
|
||||
Examples of **correct** code for this rule
|
||||
|
||||
```js
|
||||
test('foo', () => {});
|
||||
it('foo', () => {});
|
||||
|
||||
describe('foo', () => {
|
||||
test('bar', () => {});
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```ts
|
||||
interface Options {
|
||||
ignoreTypeOfDescribeName?: boolean;
|
||||
disallowedWords?: string[];
|
||||
mustNotMatch?: Partial<Record<'describe' | 'test' | 'it', string>> | string;
|
||||
mustMatch?: Partial<Record<'describe' | 'test' | 'it', string>> | string;
|
||||
}
|
||||
```
|
||||
|
||||
#### `ignoreTypeOfDescribeName`
|
||||
|
||||
Default: `false`
|
||||
|
||||
When enabled, the type of the first argument to `describe` blocks won't be
|
||||
checked.
|
||||
|
||||
#### `disallowedWords`
|
||||
|
||||
Default: `[]`
|
||||
|
||||
A string array of words that are not allowed to be used in test titles. Matching
|
||||
is not case-sensitive, and looks for complete words:
|
||||
|
||||
Examples of **incorrect** code when using `disallowedWords`:
|
||||
|
||||
```js
|
||||
// with disallowedWords: ['correct', 'all', 'every', 'properly']
|
||||
describe('the correct way to do things', () => {});
|
||||
it('has ALL the things', () => {});
|
||||
xdescribe('every single one of them', () => {});
|
||||
test(`that the value is set properly`, () => {});
|
||||
```
|
||||
|
||||
Examples of **correct** code when using `disallowedWords`:
|
||||
|
||||
```js
|
||||
// with disallowedWords: ['correct', 'all', 'every', 'properly']
|
||||
it('correctly sets the value', () => {});
|
||||
test('that everything is as it should be', () => {});
|
||||
describe('the proper way to handle things', () => {});
|
||||
```
|
||||
|
||||
#### `mustMatch` & `mustNotMatch`
|
||||
|
||||
Defaults: `{}`
|
||||
|
||||
Allows enforcing that titles must match or must not match a given Regular
|
||||
Expression, with an optional message. An object can be provided to apply
|
||||
different Regular Expressions (with optional messages) to specific Jest test
|
||||
function groups (`describe`, `test`, and `it`).
|
||||
|
||||
Examples of **incorrect** code when using `mustMatch`:
|
||||
|
||||
```js
|
||||
// with mustMatch: '^that'
|
||||
describe('the correct way to do things', () => {});
|
||||
fit('this there!', () => {});
|
||||
|
||||
// with mustMatch: { test: '^that' }
|
||||
describe('the tests that will be run', () => {});
|
||||
test('the stuff works', () => {});
|
||||
xtest('errors that are thrown have messages', () => {});
|
||||
```
|
||||
|
||||
Examples of **correct** code when using `mustMatch`:
|
||||
|
||||
```js
|
||||
// with mustMatch: '^that'
|
||||
describe('that thing that needs to be done', () => {});
|
||||
fit('that this there!', () => {});
|
||||
|
||||
// with mustMatch: { test: '^that' }
|
||||
describe('the tests that will be run', () => {});
|
||||
test('that the stuff works', () => {});
|
||||
xtest('that errors that thrown have messages', () => {});
|
||||
```
|
||||
|
||||
Optionally you can provide a custom message to show for a particular matcher by
|
||||
using a tuple at any level where you can provide a matcher:
|
||||
|
||||
```js
|
||||
const prefixes = ['when', 'with', 'without', 'if', 'unless', 'for'];
|
||||
const prefixesList = prefixes.join(' - \n');
|
||||
|
||||
module.exports = {
|
||||
rules: {
|
||||
'jest/valid-title': [
|
||||
'error',
|
||||
{
|
||||
mustNotMatch: ['\\.$', 'Titles should not end with a full-stop'],
|
||||
mustMatch: {
|
||||
describe: [
|
||||
new RegExp(`^(?:[A-Z]|\\b(${prefixes.join('|')})\\b`, 'u').source,
|
||||
`Describe titles should either start with a capital letter or one of the following prefixes: ${prefixesList}`,
|
||||
],
|
||||
test: [/[^A-Z]/u.source],
|
||||
it: /[^A-Z]/u.source,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
Reference in New Issue
Block a user