Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(require-tothrow-message): rename rule to require-to-throw-message #306

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -141,7 +141,7 @@ installations requiring long-term consistency.
| [prefer-to-have-length][] | Suggest using `toHaveLength()` | | ![fixable-green][] |
| [prefer-todo][] | Suggest using `test.todo()` | | ![fixable-green][] |
| [require-top-level-describe][] | Require a top-level `describe` block | | |
| [require-tothrow-message][] | Require that `toThrow()` and `toThrowError` includes a message | | |
| [require-to-throw-message][] | Require that `toThrow()` and `toThrowError` includes a message | | |
| [valid-describe][] | Enforce valid `describe()` callback | ![recommended][] | |
| [valid-expect-in-promise][] | Enforce having return statement when testing with promises | ![recommended][] | |
| [valid-expect][] | Enforce valid `expect()` usage | ![recommended][] | |
Expand Down Expand Up @@ -195,7 +195,7 @@ https://github.com/dangreenisrael/eslint-plugin-jest-formatting
[prefer-to-have-length]: docs/rules/prefer-to-have-length.md
[prefer-todo]: docs/rules/prefer-todo.md
[require-top-level-describe]: docs/rules/require-top-level-describe.md
[require-tothrow-message]: docs/rules/require-tothrow-message.md
SimenB marked this conversation as resolved.
Show resolved Hide resolved
[require-to-throw-message]: docs/rules/require-to-throw-message.md
[valid-describe]: docs/rules/valid-describe.md
[valid-expect-in-promise]: docs/rules/valid-expect-in-promise.md
[valid-expect]: docs/rules/valid-expect.md
Expand Down
10 changes: 9 additions & 1 deletion src/__tests__/rules.test.ts
Expand Up @@ -2,7 +2,15 @@ import { existsSync } from 'fs';
import { resolve } from 'path';
import plugin from '../';

const ruleNames = Object.keys(plugin.rules);
const excludeRules = [
// require-tothrow-message has been renamed to require-to-throw-message, remove in major version bump
'require-tothrow-message',
];

const ruleNames = Object.keys(plugin.rules).filter(
rule => !excludeRules.includes(rule),
);

const numberOfRules = 39;

describe('rules', () => {
Expand Down
@@ -1,13 +1,14 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';
import rule from '../require-tothrow-message';
import rule from '../require-to-throw-message';
import deprecatedRule from '../require-tothrow-message'; // remove in major version bump

const ruleTester = new TSESLint.RuleTester({
parserOptions: {
ecmaVersion: 8,
},
});

ruleTester.run('require-tothrow-message', rule, {
ruleTester.run('require-to-throw-message', rule, {
valid: [
// String
"expect(() => { throw new Error('a'); }).toThrow('a');",
Expand Down Expand Up @@ -66,8 +67,8 @@ ruleTester.run('require-tothrow-message', rule, {
code: "expect(() => { throw new Error('a'); }).toThrow();",
errors: [
{
messageId: 'requireRethrow',
data: { propertyName: 'toThrow' },
messageId: 'addErrorMessage',
data: { matcherName: 'toThrow' },
column: 41,
line: 1,
},
Expand All @@ -78,8 +79,8 @@ ruleTester.run('require-tothrow-message', rule, {
code: "expect(() => { throw new Error('a'); }).toThrowError();",
errors: [
{
messageId: 'requireRethrow',
data: { propertyName: 'toThrowError' },
messageId: 'addErrorMessage',
data: { matcherName: 'toThrowError' },
column: 41,
line: 1,
},
Expand All @@ -95,18 +96,37 @@ ruleTester.run('require-tothrow-message', rule, {
})`,
errors: [
{
messageId: 'requireRethrow',
data: { propertyName: 'toThrow' },
messageId: 'addErrorMessage',
data: { matcherName: 'toThrow' },
column: 49,
line: 3,
},
{
messageId: 'requireRethrow',
data: { propertyName: 'toThrowError' },
messageId: 'addErrorMessage',
data: { matcherName: 'toThrowError' },
column: 49,
line: 4,
},
],
},
],
});

// remove in major version bump
ruleTester.run('require-tothrow-message', deprecatedRule, {
valid: ["expect(() => { throw new Error('a'); }).toThrow('a');"],

invalid: [
{
code: "expect(() => { throw new Error('a'); }).toThrow();",
errors: [
{
messageId: 'addErrorMessage',
data: { matcherName: 'toThrow' },
column: 41,
line: 1,
},
],
},
],
});
50 changes: 50 additions & 0 deletions src/rules/require-to-throw-message.ts
@@ -0,0 +1,50 @@
import {
ModifierName,
createRule,
isExpectCall,
parseExpectCall,
} from './utils';

export default createRule({
name: __filename,
meta: {
docs: {
category: 'Best Practices',
description: 'Require a message for `toThrow()`',
recommended: false,
},
messages: {
addErrorMessage: 'Add an error message to {{ propertyName }}()',
},
type: 'suggestion',
schema: [],
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
if (!isExpectCall(node)) {
return;
}

const { matcher, modifier } = parseExpectCall(node);

if (
matcher &&
matcher.arguments &&
matcher.arguments.length === 0 &&
['toThrow', 'toThrowError'].includes(matcher.name) &&
(!modifier ||
!(modifier.name === ModifierName.not || modifier.negation))
) {
// Look for `toThrow` calls with no arguments.
context.report({
messageId: 'addErrorMessage',
data: { matcherName: matcher.name },
node: matcher.node.property,
});
}
},
};
},
});
56 changes: 9 additions & 47 deletions src/rules/require-tothrow-message.ts
@@ -1,50 +1,12 @@
import {
ModifierName,
createRule,
isExpectCall,
parseExpectCall,
} from './utils';
import requireToThrowMessage from './require-to-throw-message';

export default createRule({
name: __filename,
meta: {
docs: {
category: 'Best Practices',
description: 'Require a message for `toThrow()`',
recommended: false,
},
messages: {
requireRethrow: 'Add an error message to {{ propertyName }}()',
},
type: 'suggestion',
schema: [],
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
if (!isExpectCall(node)) {
return;
}
// remove this file in major version bump

const { matcher, modifier } = parseExpectCall(node);

if (
matcher &&
matcher.arguments &&
matcher.arguments.length === 0 &&
['toThrow', 'toThrowError'].includes(matcher.name) &&
(!modifier ||
!(modifier.name === ModifierName.not || modifier.negation))
) {
// Look for `toThrow` calls with no arguments.
context.report({
messageId: 'requireRethrow', // todo: rename to 'addErrorMessage'
data: { propertyName: matcher.name }, // todo: rename to 'matcherName'
node: matcher.node.property,
});
}
},
};
export default {
...requireToThrowMessage,
meta: {
...requireToThrowMessage.meta,
deprecated: true,
replacedBy: ['require-to-throw-message'],
},
});
};