Skip to content

Commit

Permalink
feat(expect-expect): support additionalTestBlockFunctions option
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath committed Jun 19, 2021
1 parent 9f4f669 commit 8e00541
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 12 deletions.
43 changes: 42 additions & 1 deletion docs/rules/expect-expect.md
Expand Up @@ -34,7 +34,8 @@ it('should work with callbacks/async', () => {
"jest/expect-expect": [
"error",
{
"assertFunctionNames": ["expect"]
"assertFunctionNames": ["expect"],
"additionalTestBlockFunctions": []
}
]
}
Expand Down Expand Up @@ -102,3 +103,43 @@ describe('GET /user', function () {
});
});
```

### `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);
},
);
});
```
50 changes: 49 additions & 1 deletion src/rules/__tests__/expect-expect.test.ts
Expand Up @@ -15,6 +15,7 @@ const ruleTester = new TSESLint.RuleTester({

ruleTester.run('expect-expect', rule, {
valid: [
"['x']();",
'it("should pass", () => expect(true).toBeDefined())',
'test("should pass", () => expect(true).toBeDefined())',
'it("should pass", () => somePromise().then(() => expect(true).toBeDefined()))',
Expand Down Expand Up @@ -69,7 +70,21 @@ ruleTester.run('expect-expect', rule, {
},
{
code: 'it("should pass", () => expect(true).toBeDefined())',
options: [{ assertFunctionNames: undefined }],
options: [
{
assertFunctionNames: undefined,
additionalTestBlockFunctions: undefined,
},
],
},
{
code: dedent`
theoretically('the number {input} is correctly translated to string', theories, theory => {
const output = NumberToLongString(theory.input);
expect(output).toBe(theory.expected);
})
`,
options: [{ additionalTestBlockFunctions: ['theoretically'] }],
},
],

Expand Down Expand Up @@ -101,6 +116,39 @@ ruleTester.run('expect-expect', rule, {
},
],
},
{
code: 'test.skip("should fail", () => {});',
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: 'afterEach(() => {});',
options: [{ additionalTestBlockFunctions: ['afterEach'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: dedent`
theoretically('the number {input} is correctly translated to string', theories, theory => {
const output = NumberToLongString(theory.input);
})
`,
options: [{ additionalTestBlockFunctions: ['theoretically'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: 'it("should fail", () => { somePromise.then(() => {}); });',
errors: [
Expand Down
34 changes: 24 additions & 10 deletions src/rules/expect-expect.ts
Expand Up @@ -8,10 +8,10 @@ import {
TSESTree,
} from '@typescript-eslint/experimental-utils';
import {
TestCaseName,
createRule,
getNodeName,
getTestCallExpressionsFromDeclaredVariables,
isTestCaseCall,
} from './utils';

/**
Expand Down Expand Up @@ -41,7 +41,12 @@ function matchesAssertFunctionName(
}

export default createRule<
[Partial<{ assertFunctionNames: readonly string[] }>],
[
Partial<{
assertFunctionNames: readonly string[];
additionalTestBlockFunctions: readonly string[];
}>,
],
'noAssertions'
>({
name: __filename,
Expand All @@ -62,14 +67,23 @@ export default createRule<
type: 'array',
items: [{ type: 'string' }],
},
additionalTestBlockFunctions: {
type: 'array',
items: { type: 'string' },
},
},
additionalProperties: false,
},
],
type: 'suggestion',
},
defaultOptions: [{ assertFunctionNames: ['expect'] }],
create(context, [{ assertFunctionNames = ['expect'] }]) {
defaultOptions: [
{ assertFunctionNames: ['expect'], additionalTestBlockFunctions: [] },
],
create(
context,
[{ assertFunctionNames = ['expect'], additionalTestBlockFunctions = [] }],
) {
const unchecked: TSESTree.CallExpression[] = [];

function checkCallExpressionUsed(nodes: TSESTree.Node[]) {
Expand All @@ -96,14 +110,14 @@ export default createRule<

return {
CallExpression(node) {
const name = getNodeName(node.callee);
const name = getNodeName(node.callee) ?? '';

if (name === TestCaseName.it || name === TestCaseName.test) {
unchecked.push(node);
} else if (
name &&
matchesAssertFunctionName(name, assertFunctionNames)
if (
isTestCaseCall(node) ||
additionalTestBlockFunctions.includes(name)
) {
unchecked.push(node);
} else if (matchesAssertFunctionName(name, assertFunctionNames)) {
// Return early in case of nested `it` statements.
checkCallExpressionUsed(context.getAncestors());
}
Expand Down

0 comments on commit 8e00541

Please sign in to comment.