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

Add lowercase-description rule #56

Merged
merged 3 commits into from
Feb 12, 2018
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ for more information about extending configuration files.
| Rule | Description | Recommended | Fixable |
| ------------------------------------------------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------- |
| [consistent-test-it](docs/rules/consistent-test-it.md) | Enforce consistent test or it keyword | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
| [lowercase-name](docs/rules/lowercase-name.md) | Disallow capitalized test names | | |
| [no-disabled-tests](docs/rules/no-disabled-tests.md) | Disallow disabled tests | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
| [no-focused-tests](docs/rules/no-focused-tests.md) | Disallow focused tests | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
| [no-hooks](docs/rules/no-hooks.md) | Disallow setup and teardown hooks | | |
Expand Down
23 changes: 23 additions & 0 deletions docs/rules/lowercase-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Enforce lowercase test names (lowercase-name)

## Rule details

Enforce `it`, `test` and `describe` to have descriptions that begin with a
lowercase letter. This provides more readable test failures. This rule is not
enabled by default.

The following pattern is considered a warning:

```js
it('Adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
```

The following pattern is not considered a warning:

```js
it('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
```
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const consistentTestIt = require('./rules/consistent-test-it');
const lowercaseName = require('./rules/lowercase-name');
const noDisabledTests = require('./rules/no-disabled-tests');
const noFocusedTests = require('./rules/no-focused-tests');
const noHooks = require('./rules/no-hooks');
Expand Down Expand Up @@ -61,6 +62,7 @@ module.exports = {
},
rules: {
'consistent-test-it': consistentTestIt,
'lowercase-name': lowercaseName,
'no-disabled-tests': noDisabledTests,
'no-focused-tests': noFocusedTests,
'no-hooks': noHooks,
Expand Down
130 changes: 130 additions & 0 deletions rules/__tests__/lowercase-name.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
'use strict';

const RuleTester = require('eslint').RuleTester;
const rules = require('../..').rules;

const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 6,
},
});

ruleTester.run('lowercase-name', rules['lowercase-name'], {
valid: [
"it(' ', function () {})",
'it(" ", function () {})',
'it(` `, function () {})',
"it('foo', function () {})",
'it("foo", function () {})',
'it(`foo`, function () {})',
'it("<Foo/>", function () {})',
'it("123 foo", function () {})',
'it(42, function () {})',
"test('foo', function () {})",
'test("foo", function () {})',
'test(`foo`, function () {})',
'test("<Foo/>", function () {})',
'test("123 foo", function () {})',
'test("42", function () {})',
"describe('foo', function () {})",
'describe("foo", function () {})',
'describe(`foo`, function () {})',
'describe("<Foo/>", function () {})',
'describe("123 foo", function () {})',
'describe("42", function () {})',
'describe(function () {})',
],

invalid: [
{
code: "it('Foo', function () {})",
errors: [
{
message: '`it`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: 'it("Foo", function () {})',
errors: [
{
message: '`it`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: 'it(`Foo`, function () {})',
errors: [
{
message: '`it`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: "test('Foo', function () {})",
errors: [
{
message: '`test`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: 'test("Foo", function () {})',
errors: [
{
message: '`test`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: 'test(`Foo`, function () {})',
errors: [
{
message: '`test`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: "describe('Foo', function () {})",
errors: [
{
message: '`describe`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: 'describe("Foo", function () {})',
errors: [
{
message: '`describe`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
{
code: 'describe(`Foo`, function () {})',
errors: [
{
message: '`describe`s should begin with lowercase',
column: 1,
line: 1,
},
],
},
],
});
70 changes: 70 additions & 0 deletions rules/lowercase-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict';

const isItTestOrDescribeFunction = node => {
return (
node.type === 'CallExpression' &&
node.callee &&
(node.callee.name === 'it' ||
node.callee.name === 'test' ||
node.callee.name === 'describe')
);
};

const isItDescription = node => {
return (
node.arguments &&
node.arguments[0] &&
(node.arguments[0].type === 'Literal' ||
node.arguments[0].type === 'TemplateLiteral')
);
};

const testDescription = node => {
const firstArgument = node.arguments[0];
const type = firstArgument.type;

if (type === 'Literal') {
return firstArgument.value;
}

// `isItDescription` guarantees this is `type === 'TemplateLiteral'`
return firstArgument.quasis[0].value.raw;
};

const descriptionBeginsWithLowerCase = node => {
if (isItTestOrDescribeFunction(node) && isItDescription(node)) {
const description = testDescription(node);
if (!description[0]) {
return false;
}

if (description[0] !== description[0].toLowerCase()) {
return node.callee.name;
}
}
return false;
};

module.exports = {
meta: {
docs: {
url:
'https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/lowercase-name.md',
},
},
create(context) {
return {
CallExpression(node) {
const erroneousMethod = descriptionBeginsWithLowerCase(node);

if (erroneousMethod) {
context.report({
message: '`{{ method }}`s should begin with lowercase',
data: { method: erroneousMethod },
node: node,
});
}
},
};
},
};