Rules for consistent function style and arrow function usage in Mocha test suites.
Prevents arrow functions in Mocha tests where this context is needed for timeouts and other Mocha features.
/**
* Disallows arrow functions in Mocha tests
* Prevents issues with 'this' context binding in Mocha
*/
const noMochaArrowsRule = {
meta: {
type: 'problem',
docs: {
description: 'Disallow arrow functions as arguments to Mocha functions',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-mocha-arrows.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-mocha-arrows": "error"
}
}Examples:
// ✓ Good - regular functions that preserve 'this' context
describe('Calculator', function() {
it('should handle timeout', function() {
this.timeout(5000); // 'this' context available
// Test implementation
});
beforeEach(function() {
this.calculator = new Calculator();
});
});
// ✗ Bad - arrow functions lose 'this' context
describe('Calculator', () => { // Not allowed
it('should handle timeout', () => { // Not allowed
this.timeout(5000); // 'this' is undefined
// Test implementation
});
beforeEach(() => { // Not allowed
this.calculator = new Calculator(); // 'this' is undefined
});
});Enforces arrow functions for test callbacks when this context is not needed, promoting consistent style.
/**
* Prefers arrow functions for test callbacks
* Promotes consistent modern JavaScript style when 'this' is not needed
*/
const preferArrowCallbackRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Prefer arrow function callbacks',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/prefer-arrow-callback.md'
},
fixable: 'code',
schema: [{
type: 'object',
properties: {
allowNamedFunctions: {
type: 'boolean',
default: false
},
allowUnboundThis: {
type: 'boolean',
default: true
}
},
additionalProperties: false
}]
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/prefer-arrow-callback": ["error", {
"allowNamedFunctions": false,
"allowUnboundThis": true
}]
}
}Examples:
// ✓ Good - arrow functions when 'this' not needed
describe('Calculator', function() {
it('should add numbers', () => {
const result = add(1, 2);
assert.equal(result, 3);
});
it('should subtract numbers', () => {
const result = subtract(5, 2);
assert.equal(result, 3);
});
});
// ✗ Bad - regular functions when arrow would suffice
describe('Calculator', function() {
it('should add numbers', function() { // Could be arrow function
const result = add(1, 2);
assert.equal(result, 3);
});
});
// ✓ Good - regular function when using 'this'
describe('Calculator', function() {
it('should handle timeout', function() {
this.timeout(5000); // Needs 'this' context
const result = slowOperation();
assert.equal(result, 'done');
});
});Prevents async functions in describe blocks, which can cause unexpected behavior in test execution.
/**
* Disallows async functions in describe blocks
* Prevents unexpected behavior in test suite execution
*/
const noAsyncDescribeRule = {
meta: {
type: 'problem',
docs: {
description: 'Disallow async functions passed to describe',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-async-describe.md'
},
schema: []
},
create: (context) => ESLintVisitor
};Usage:
{
"rules": {
"mocha/no-async-describe": "error"
}
}Examples:
// ✓ Good - regular function in describe
describe('UserService', function() {
let userService;
beforeEach(function() {
userService = new UserService();
});
it('should create user', async function() {
const user = await userService.create('John');
assert.equal(user.name, 'John');
});
});
// ✗ Bad - async function in describe
describe('UserService', async function() { // Not allowed
let userService;
beforeEach(function() {
userService = new UserService();
});
it('should create user', async function() {
const user = await userService.create('John');
assert.equal(user.name, 'John');
});
});
// ✗ Bad - async arrow in describe
describe('UserService', async () => { // Not allowed
// Tests
});{
"rules": {
"mocha/no-mocha-arrows": "error",
"mocha/prefer-arrow-callback": ["warn", {
"allowNamedFunctions": false,
"allowUnboundThis": true
}],
"mocha/no-async-describe": "error"
}
}{
"rules": {
"mocha/no-mocha-arrows": "error",
"mocha/prefer-arrow-callback": "off",
"mocha/no-async-describe": "error"
}
}{
"rules": {
"mocha/no-mocha-arrows": "warn",
"mocha/prefer-arrow-callback": ["error", {
"allowNamedFunctions": true,
"allowUnboundThis": false
}],
"mocha/no-async-describe": "error"
}
}// ✓ Best practices - mixed approach based on context
// Use regular functions for describe blocks
describe('UserService', function() {
let userService;
// Use regular functions when you need 'this' context
beforeEach(function() {
this.timeout(10000);
userService = new UserService();
});
// Use arrow functions for simple tests without 'this'
it('should create user with valid data', () => {
const user = userService.create('John', 'john@example.com');
assert.equal(user.name, 'John');
assert.equal(user.email, 'john@example.com');
});
// Use regular functions for async tests with 'this'
it('should handle slow operations', function() {
this.timeout(30000);
return userService.slowOperation().then(result => {
assert.equal(result.status, 'completed');
});
});
// Use async functions for async/await patterns
it('should handle async operations', async () => {
const result = await userService.asyncOperation();
assert.equal(result.success, true);
});
// Use regular functions with done callback
it('should handle callback-based async', function(done) {
userService.callbackOperation((err, result) => {
if (err) return done(err);
assert.equal(result.status, 'ok');
done();
});
});
});
// Nested describe blocks - regular functions
describe('UserService', function() {
describe('#create', function() {
it('should validate input', () => {
assert.throws(() => userService.create(''), /Name required/);
});
});
describe('#update', function() {
beforeEach(function() {
this.existingUser = userService.create('John', 'john@example.com');
});
it('should update user properties', () => {
const updated = userService.update(this.existingUser.id, {
email: 'newemail@example.com'
});
assert.equal(updated.email, 'newemail@example.com');
});
});
});