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

feat(valid-title): support disallowedWords option #522

Merged
merged 6 commits into from Feb 7, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
48 changes: 45 additions & 3 deletions docs/rules/valid-title.md
Expand Up @@ -45,7 +45,7 @@ xtest('foo', () => {});

Titles for test blocks should always be a string literal or expression.

This is also applied to describe blocks by default, but can be turned off via
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:
Expand Down Expand Up @@ -87,7 +87,7 @@ describe(6, function() {});

**duplicatePrefix**

A describe/ test block should not start with duplicatePrefix
A `describe` / `test` block should not start with `duplicatePrefix`

Examples of **incorrect** code for this rule

Expand Down Expand Up @@ -117,7 +117,7 @@ describe('foo', () => {

**accidentalSpace**

A describe/ test block should not contain accidentalSpace
A `describe` / `test` block should not contain accidentalSpace

Examples of **incorrect** code for this rule

Expand Down Expand Up @@ -148,3 +148,45 @@ describe('foo', () => {
test('bar', () => {});
});
```

## Options

```ts
interface {
ignoreTypeOfDescribeName?: boolean;
disallowedWords?: 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:
G-Rath marked this conversation as resolved.
Show resolved Hide resolved

Examples of **incorrect** code 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', () => {});
```
89 changes: 88 additions & 1 deletion src/rules/__tests__/valid-title.test.ts
Expand Up @@ -9,6 +9,93 @@ const ruleTester = new TSESLint.RuleTester({
},
});

ruleTester.run('disallowedWords option', rule, {
valid: [
'describe("the correct way to properly handle all the things", () => {});',
'test("that all is as it should be", () => {});',
{
code: 'it("correctly sets the value", () => {});',
options: [
{ ignoreTypeOfDescribeName: false, disallowedWords: ['correct'] },
],
},
],
invalid: [
{
code: 'test("the correct way to properly handle all things", () => {});',
options: [{ disallowedWords: ['correct', 'properly', 'all'] }],
errors: [
{
messageId: 'disallowedWord',
data: { word: 'correct' },
column: 6,
line: 1,
},
],
},
{
code: 'describe("the correct way to do things", function () {})',
options: [{ disallowedWords: ['correct'] }],
errors: [
{
messageId: 'disallowedWord',
data: { word: 'correct' },
column: 10,
line: 1,
},
],
},
{
code: 'it("has ALL the things", () => {})',
options: [{ disallowedWords: ['all'] }],
errors: [
{
messageId: 'disallowedWord',
data: { word: 'ALL' },
column: 4,
line: 1,
},
],
},
{
code: 'xdescribe("every single one of them", function () {})',
options: [{ disallowedWords: ['every'] }],
errors: [
{
messageId: 'disallowedWord',
data: { word: 'every' },
column: 11,
line: 1,
},
],
},
{
code: "describe('Very Descriptive Title Goes Here', function () {})",
options: [{ disallowedWords: ['descriptive'] }],
errors: [
{
messageId: 'disallowedWord',
data: { word: 'Descriptive' },
column: 10,
line: 1,
},
],
},
{
code: 'test(`that the value is set properly`, function () {})',
options: [{ disallowedWords: ['properly'] }],
errors: [
{
messageId: 'disallowedWord',
data: { word: 'properly' },
column: 6,
line: 1,
},
],
},
],
});

ruleTester.run('title-must-be-string', rule, {
valid: [
'it("is a string", () => {});',
Expand All @@ -31,7 +118,7 @@ ruleTester.run('title-must-be-string', rule, {
},
{
code: 'xdescribe(skipFunction, () => {});',
options: [{ ignoreTypeOfDescribeName: true }],
options: [{ ignoreTypeOfDescribeName: true, disallowedWords: [] }],
G-Rath marked this conversation as resolved.
Show resolved Hide resolved
},
],
invalid: [
Expand Down
29 changes: 27 additions & 2 deletions src/rules/valid-title.ts
Expand Up @@ -50,6 +50,7 @@ export default createRule({
emptyTitle: '{{ jestFunctionName }} should not have an empty title',
duplicatePrefix: 'should not have duplicate prefix',
accidentalSpace: 'should not have leading or trailing spaces',
disallowedWord: '"{{ word }}" is not allowed in test titles.',
},
type: 'suggestion',
schema: [
Expand All @@ -60,14 +61,24 @@ export default createRule({
type: 'boolean',
default: false,
},
disallowedWords: {
type: 'array',
items: { type: 'string' },
default: [],
},
},
additionalProperties: false,
},
],
fixable: 'code',
},
defaultOptions: [{ ignoreTypeOfDescribeName: false }],
create(context, [{ ignoreTypeOfDescribeName }]) {
defaultOptions: [{ ignoreTypeOfDescribeName: false, disallowedWords: [] }],
create(context, [{ ignoreTypeOfDescribeName, disallowedWords }]) {
const disallowedWordsRegexp = new RegExp(
`\\b(${disallowedWords.join('|')})\\b`,
'iu',
);

return {
CallExpression(node: TSESTree.CallExpression) {
if (!(isDescribe(node) || isTestCase(node)) || !node.arguments.length) {
Expand Down Expand Up @@ -113,6 +124,20 @@ export default createRule({
return;
}

if (disallowedWords.length > 0) {
const disallowedMatch = disallowedWordsRegexp.exec(title);

if (disallowedMatch) {
context.report({
data: { word: disallowedMatch[1] },
messageId: 'disallowedWord',
node: argument,
});

return;
}
}

if (title.trim().length !== title.length) {
context.report({
messageId: 'accidentalSpace',
Expand Down