Rules that enforce proper test organization, structure, and prevent anti-patterns in Mocha test suites.
Prevents nested test cases which can lead to confusing test hierarchies and execution order issues.
/**
* Disallows nested test cases within other tests
* Prevents confusing test structure and execution issues
*/
const noNestedTestsRule = {
meta: {
type: 'problem',
docs: {
description: 'Disallow nested tests',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-nested-tests.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-nested-tests": "error"
}
}Examples:
// ✓ Good - flat test structure
describe('Calculator', function() {
it('should add numbers', function() {
assert.equal(add(1, 2), 3);
});
it('should subtract numbers', function() {
assert.equal(subtract(5, 2), 3);
});
});
// ✗ Bad - nested test within test
describe('Calculator', function() {
it('should perform operations', function() {
assert.equal(add(1, 2), 3);
// Nested test - not allowed
it('should also subtract', function() {
assert.equal(subtract(5, 2), 3);
});
});
});Prevents setup code execution directly in describe blocks, ensuring proper test isolation.
/**
* Disallows setup code in describe blocks
* Ensures proper test isolation and prevents side effects
*/
const noSetupInDescribeRule = {
meta: {
type: 'problem',
docs: {
description: 'Disallow setup in describe blocks',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-setup-in-describe.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-setup-in-describe": "error"
}
}Examples:
// ✓ Good - setup in hooks
describe('UserService', function() {
let userService;
beforeEach(function() {
userService = new UserService();
});
it('should create user', function() {
const user = userService.create('John');
assert.equal(user.name, 'John');
});
});
// ✗ Bad - setup directly in describe
describe('UserService', function() {
const userService = new UserService(); // Setup in describe
userService.initialize(); // Side effect in describe
it('should create user', function() {
const user = userService.create('John');
assert.equal(user.name, 'John');
});
});Disallows hooks (before, after, beforeEach, afterEach) when there's only one test case in a suite.
/**
* Disallows hooks for single test case suites
* Prevents unnecessary complexity for simple test suites
*/
const noHooksForSingleCaseRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow hooks for a single test case',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-hooks-for-single-case.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-hooks-for-single-case": "error"
}
}Prevents multiple hooks of the same type (e.g., multiple beforeEach) in the same scope.
/**
* Disallows sibling hooks of the same type
* Prevents confusing hook execution order
*/
const noSiblingHooksRule = {
meta: {
type: 'problem',
docs: {
description: 'Disallow sibling hooks',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-sibling-hooks.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-sibling-hooks": "error"
}
}Examples:
// ✓ Good - single hook of each type
describe('Service', function() {
beforeEach(function() {
// Setup
});
afterEach(function() {
// Cleanup
});
it('should work', function() {
// Test
});
});
// ✗ Bad - multiple hooks of same type
describe('Service', function() {
beforeEach(function() {
// First setup
});
beforeEach(function() {
// Second setup - not allowed
});
it('should work', function() {
// Test
});
});Disallows hooks at the top level (outside of describe blocks).
/**
* Disallows top-level hooks outside describe blocks
* Ensures hooks are properly scoped to test suites
*/
const noTopLevelHooksRule = {
meta: {
type: 'problem',
docs: {
description: 'Disallow top-level hooks',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-top-level-hooks.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-top-level-hooks": "error"
}
}Completely disallows all hooks (before, after, beforeEach, afterEach) in test files.
/**
* Disallows all hooks in tests
* Enforces direct setup/teardown in test functions
*/
const noHooksRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow hooks',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-hooks.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-hooks": "error"
}
}{
"rules": {
"mocha/no-nested-tests": "error",
"mocha/no-setup-in-describe": "error",
"mocha/no-hooks-for-single-case": "warn",
"mocha/no-sibling-hooks": "error",
"mocha/no-top-level-hooks": "error",
"mocha/no-hooks": "off"
}
}{
"rules": {
"mocha/no-nested-tests": "error",
"mocha/no-setup-in-describe": "error",
"mocha/no-hooks-for-single-case": "error",
"mocha/no-sibling-hooks": "error",
"mocha/no-top-level-hooks": "error",
"mocha/no-hooks": "error"
}
}// ✓ Good - proper test structure
describe('UserService', function() {
let userService;
let database;
before(function() {
database = new TestDatabase();
});
beforeEach(function() {
userService = new UserService(database);
});
afterEach(function() {
userService.cleanup();
});
after(function() {
database.close();
});
describe('#create', function() {
it('should create a new user', function() {
const user = userService.create('John', 'john@example.com');
assert.equal(user.name, 'John');
assert.equal(user.email, 'john@example.com');
});
it('should validate email format', function() {
assert.throws(() => {
userService.create('John', 'invalid-email');
}, /Invalid email format/);
});
});
describe('#update', function() {
beforeEach(function() {
userService.create('John', 'john@example.com');
});
it('should update user details', function() {
const updated = userService.update('John', { email: 'newemail@example.com' });
assert.equal(updated.email, 'newemail@example.com');
});
});
});