Skip to content

Commit

Permalink
Implement new rule consistent-interface
Browse files Browse the repository at this point in the history
  • Loading branch information
lo1tuma committed Jan 23, 2025
1 parent 4a02c4c commit 161b118
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ See [Configuring Eslint](http://eslint.org/docs/user-guide/configuring) on [esli

| Name                              | Description | 💼 | ⚠️ | 🚫 | 🔧 |
| :----------------------------------------------------------------------------------- | :---------------------------------------------------------------------- | :- | :- | :- | :- |
| [consistent-interface](docs/rules/consistent-interface.md) | Enforces consistent use of mocha interfaces | | | | |
| [consistent-spacing-between-blocks](docs/rules/consistent-spacing-between-blocks.md) | Require consistent spacing between blocks || | | 🔧 |
| [handle-done-callback](docs/rules/handle-done-callback.md) | Enforces handling of callbacks for async tests || | | |
| [max-top-level-suites](docs/rules/max-top-level-suites.md) | Enforce the number of top-level suites in a single file || | | |
Expand Down
23 changes: 23 additions & 0 deletions docs/rules/consistent-interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Enforces consistent use of mocha interfaces (`mocha/consistent-interface`)

<!-- end auto-generated rule header -->

Mocha has several interfaces such as `BDD`, `TDD`, `Exports`, `QUnit` etc. Usually mocha works by injecting the variables and functions of the selected interface into the global scope. However when using the `Exports` interface one can import functions of any interface. This rule helps to enforce a consistent use of the same interface when using `Exports`.

## Options

Example of a custom rule configuration:

```js
rules: {
"mocha/consistent-interface": ["error", { interface: 'BDD' }]
},
```

where:

- `interface` can be set to either `TDD` or `BDD`

## When Not To Use It

If you are not using the `Exports` interface then this rule doesn’t provide any value.
7 changes: 5 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import globals from 'globals';
import { consistentInterfaceRule } from './lib/rules/consistent-interface.js';
import { consistentSpacingBetweenBlocksRule } from './lib/rules/consistent-spacing-between-blocks.js';
import { handleDoneCallbackRule } from './lib/rules/handle-done-callback.js';
import { maxTopLevelSuitesRule } from './lib/rules/max-top-level-suites.js';
Expand Down Expand Up @@ -46,7 +47,8 @@ const allRules = {
'mocha/valid-suite-description': 'error',
'mocha/valid-test-description': 'error',
'mocha/no-empty-description': 'error',
'mocha/consistent-spacing-between-blocks': 'error'
'mocha/consistent-spacing-between-blocks': 'error',
'mocha/consistent-interface': ['error', { interface: 'BDD' }]
};

const recommendedRules = {
Expand Down Expand Up @@ -99,7 +101,8 @@ const mochaPlugin = {
'valid-suite-description': validSuiteDescriptionRule,
'valid-test-description': validTestDescriptionRule,
'no-empty-description': noEmptyDescriptionRule,
'consistent-spacing-between-blocks': consistentSpacingBetweenBlocksRule
'consistent-spacing-between-blocks': consistentSpacingBetweenBlocksRule,
'consistent-interface': consistentInterfaceRule
},
configs: {
all: {
Expand Down
3 changes: 2 additions & 1 deletion lib/ast/mochaVisitors.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ function createContext(reference) {
name: reference.resolvedPath.join('.'),
node: reference.node,
type: reference.nameDetails.type,
modifier: reference.nameDetails.modifier
modifier: reference.nameDetails.modifier,
interface: reference.nameDetails.interface
};
}

Expand Down
38 changes: 38 additions & 0 deletions lib/rules/consistent-interface.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createMochaVisitors } from '../ast/mochaVisitors.js';

export const consistentInterfaceRule = {
meta: {
type: 'problem',
docs: {
description: 'Enforces consistent use of mocha interfaces',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/consistent-interface.md'
},
schema: [
{
type: 'object',
properties: {
interface: {
type: 'string',
enum: ['BDD', 'TDD'],
default: 'BDD'
}
},
additionalProperties: false
}
]
},
create(context) {
const interfaceToUse = context.options[0].interface;

return createMochaVisitors(context, {
anyTestEntity(visitorContext) {
if (visitorContext.interface !== interfaceToUse) {
context.report({
node: visitorContext.node,
message: `Unexpected use of ${visitorContext.interface} interface instead of ${interfaceToUse}`
});
}
}
});
}
};
85 changes: 85 additions & 0 deletions test/rules/consistent-interface.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { RuleTester } from 'eslint';
import { consistentInterfaceRule } from '../../lib/rules/consistent-interface.js';

const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 2020, sourceType: 'module' } });

ruleTester.run('consistent-interface', consistentInterfaceRule, {
valid: [
{
code: `describe('foo', () => {
it('bar', () => {});
});`,
options: [{ interface: 'BDD' }],
settings: { mocha: { interface: 'BDD' } }
},
{
code: `suite('foo', () => {
test('bar', () => {});
});`,
options: [{ interface: 'TDD' }],
settings: { mocha: { interface: 'TDD' } }
},
{
code: `import {suite, test} from 'mocha'; suite('foo', () => {
test('bar', () => {});
});`,
options: [{ interface: 'TDD' }],
settings: { mocha: { interface: 'exports' } }
},
{
code: `import {describe, it} from 'mocha'; describe('foo', () => {
it('bar', () => {});
});`,
options: [{ interface: 'BDD' }],
settings: { mocha: { interface: 'exports' } }
},
{
code: `import {describe as foo, it as bar} from 'mocha'; foo('foo', () => {
bar('bar', () => {});
});`,
options: [{ interface: 'BDD' }],
settings: { mocha: { interface: 'exports' } }
}
],

invalid: [
{
code: `describe('foo', () => {
test('bar', () => {});
});`,
options: [{ interface: 'BDD' }],
settings: { mocha: { interface: 'BDD' } },
errors: [{ line: 2, column: 17, message: 'Unexpected use of TDD interface instead of BDD' }]
},
{
code: `describe('foo', () => {
test('bar', () => {});
});`,
options: [{ interface: 'TDD' }],
settings: { mocha: { interface: 'TDD' } },
errors: [{ line: 1, column: 1, message: 'Unexpected use of BDD interface instead of TDD' }]
},
{
code: `import {suite, test} from 'mocha'; suite('foo', () => {
test('bar', () => {});
});`,
options: [{ interface: 'BDD' }],
settings: { mocha: { interface: 'exports' } },
errors: [
{ line: 1, column: 36, message: 'Unexpected use of TDD interface instead of BDD' },
{ line: 2, column: 17, message: 'Unexpected use of TDD interface instead of BDD' }
]
},
{
code: `import {describe, it} from 'mocha'; describe('foo', () => {
it('bar', () => {});
});`,
options: [{ interface: 'TDD' }],
settings: { mocha: { interface: 'exports' } },
errors: [
{ line: 1, column: 37, message: 'Unexpected use of BDD interface instead of TDD' },
{ line: 2, column: 17, message: 'Unexpected use of BDD interface instead of TDD' }
]
}
]
});

0 comments on commit 161b118

Please sign in to comment.