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 mustMatch & mustNotMatch options #608

Merged
merged 1 commit into from Jul 5, 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
40 changes: 38 additions & 2 deletions docs/rules/valid-title.md
Expand Up @@ -152,9 +152,11 @@ describe('foo', () => {
## Options

```ts
interface {
interface Options {
ignoreTypeOfDescribeName?: boolean;
disallowedWords?: string[];
mustNotMatch?: Partial<Record<'describe' | 'test' | 'it', string>> | string;
mustMatch?: Partial<Record<'describe' | 'test' | 'it', string>> | string;
}
```

Expand All @@ -172,7 +174,7 @@ 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`:
Examples of **incorrect** code when using `disallowedWords`:

```js
// with disallowedWords: ['correct', 'all', 'every', 'properly']
Expand All @@ -190,3 +192,37 @@ 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. An object can be provided to apply different Regular Expressions 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', () => {});
```
217 changes: 217 additions & 0 deletions src/rules/__tests__/valid-title.test.ts
@@ -1,4 +1,5 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';
import dedent from 'dedent';
import resolveFrom from 'resolve-from';
import rule from '../valid-title';

Expand Down Expand Up @@ -100,6 +101,222 @@ ruleTester.run('disallowedWords option', rule, {
],
});

ruleTester.run('mustMatch & mustNotMatch options', 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: [{ mustMatch: undefined }],
},
{
code: 'it("correctly sets the value", () => {});',
options: [{ mustMatch: / /u.source }],
},
{
code: 'it("correctly sets the value #unit", () => {});',
options: [{ mustMatch: /#(?:unit|integration|e2e)/u.source }],
},
{
code: 'it("correctly sets the value", () => {});',
options: [{ mustMatch: /^[^#]+$|(?:#(?:unit|e2e))/u.source }],
},
{
code: 'it("correctly sets the value", () => {});',
options: [{ mustMatch: { test: /#(?:unit|integration|e2e)/u.source } }],
},
{
code: dedent`
describe('things to test', () => {
describe('unit tests #unit', () => {
it('is true', () => {
expect(true).toBe(true);
});
});

describe('e2e tests #e2e', () => {
it('is another test #jest4life', () => {});
});
});
`,
options: [{ mustMatch: { test: /^[^#]+$|(?:#(?:unit|e2e))/u.source } }],
},
],
invalid: [
{
code: dedent`
describe('things to test', () => {
describe('unit tests #unit', () => {
it('is true', () => {
expect(true).toBe(true);
});
});

describe('e2e tests #e4e', () => {
it('is another test #e2e #jest4life', () => {});
});
});
`,
options: [
{
mustNotMatch: /(?:#(?!unit|e2e))\w+/u.source,
mustMatch: /^[^#]+$|(?:#(?:unit|e2e))/u.source,
},
],
errors: [
{
messageId: 'mustNotMatch',
data: {
jestFunctionName: 'describe',
pattern: /(?:#(?!unit|e2e))\w+/u,
},
column: 12,
line: 8,
},
{
messageId: 'mustNotMatch',
data: {
jestFunctionName: 'it',
pattern: /(?:#(?!unit|e2e))\w+/u,
},
column: 8,
line: 9,
},
],
},
{
code: dedent`
describe('things to test', () => {
describe('unit tests #unit', () => {
it('is true', () => {
expect(true).toBe(true);
});
});

describe('e2e tests #e4e', () => {
it('is another test #e2e #jest4life', () => {});
});
});
`,
options: [
{
mustNotMatch: { describe: /(?:#(?!unit|e2e))\w+/u.source },
mustMatch: { describe: /^[^#]+$|(?:#(?:unit|e2e))/u.source },
},
],
errors: [
{
messageId: 'mustNotMatch',
data: {
jestFunctionName: 'describe',
pattern: /(?:#(?!unit|e2e))\w+/u,
},
column: 12,
line: 8,
},
],
},
{
code: dedent`
describe('things to test', () => {
describe('unit tests #unit', () => {
it('is true', () => {
expect(true).toBe(true);
});
});

describe('e2e tests #e4e', () => {
it('is another test #e2e #jest4life', () => {});
});
});
`,
options: [
{
mustNotMatch: { describe: /(?:#(?!unit|e2e))\w+/u.source },
mustMatch: { it: /^[^#]+$|(?:#(?:unit|e2e))/u.source },
},
],
errors: [
{
messageId: 'mustNotMatch',
data: {
jestFunctionName: 'describe',
pattern: /(?:#(?!unit|e2e))\w+/u,
},
column: 12,
line: 8,
},
],
},
{
code: 'test("the correct way to properly handle all things", () => {});',
options: [{ mustMatch: /#(?:unit|integration|e2e)/u.source }],
errors: [
{
messageId: 'mustMatch',
data: {
jestFunctionName: 'test',
pattern: /#(?:unit|integration|e2e)/u,
},
column: 6,
line: 1,
},
],
},
{
code: 'describe("the test", () => {});',
options: [
{ mustMatch: { describe: /#(?:unit|integration|e2e)/u.source } },
],
errors: [
{
messageId: 'mustMatch',
data: {
jestFunctionName: 'describe',
pattern: /#(?:unit|integration|e2e)/u,
},
column: 10,
line: 1,
},
],
},
{
code: 'xdescribe("the test", () => {});',
options: [
{ mustMatch: { describe: /#(?:unit|integration|e2e)/u.source } },
],
errors: [
{
messageId: 'mustMatch',
data: {
jestFunctionName: 'describe',
pattern: /#(?:unit|integration|e2e)/u,
},
column: 11,
line: 1,
},
],
},
{
code: 'describe.skip("the test", () => {});',
options: [
{ mustMatch: { describe: /#(?:unit|integration|e2e)/u.source } },
],
errors: [
{
messageId: 'mustMatch',
data: {
jestFunctionName: 'describe',
pattern: /#(?:unit|integration|e2e)/u,
},
column: 15,
line: 1,
},
],
},
],
});

ruleTester.run('title-must-be-string', rule, {
valid: [
'it("is a string", () => {});',
Expand Down