Skip to content

Commit

Permalink
feat(valid-title): support disallowedWords option (#522)
Browse files Browse the repository at this point in the history
* feat(valid-title): support `disallowedWords` option

* test(valid-title): include `data` in `disallowedWord` tests

* test(valid-title): add multi-disallowedWords test

* docs(valid-title): use code quotes & arrow functions

* chore(valid-title): use "greater than 0" in check

* chore(valid-title): reword `disallowedWord` message
  • Loading branch information
G-Rath committed Feb 7, 2020
1 parent 1449675 commit 38bbe93
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 6 deletions.
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:

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: [] }],
},
],
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

0 comments on commit 38bbe93

Please sign in to comment.