Configuration options for extending eslint-plugin-mocha's detection capabilities with custom test function names and patterns.
Allows defining custom test function names that the plugin should recognize in addition to the standard Mocha functions.
/**
* Plugin settings for custom test function names
* Extends detection beyond standard Mocha functions
*/
interface PluginSettings {
'mocha/additionalCustomNames'?: CustomName[];
}
interface CustomName {
/** The function name pattern to recognize */
name: string;
/** The type of Mocha function this represents */
type: 'suite' | 'testCase' | 'hook';
/** Which Mocha interfaces this name applies to */
interfaces: Array<'BDD' | 'TDD' | 'QUnit'>;
}Various patterns for custom function names to accommodate different testing extensions and frameworks.
/**
* Supported name patterns for custom functions
*/
type NamePattern =
| string // Simple name: "customTest"
| `${string}.${string}` // Dotted name: "describe.modifier"
| `${string}().${string}` // Function call: "forEach().describe"
| `${string}().${string}.${string}`; // Complex: "forEach().describe.modifier"The different Mocha testing interfaces that custom names can be associated with.
/**
* Mocha interface types for categorizing custom names
*/
enum MochaInterface {
BDD = 'BDD', // Behavior-driven development (describe, it, before, after)
TDD = 'TDD', // Test-driven development (suite, test, setup, teardown)
QUnit = 'QUnit' // QUnit style (suite, test, before, after)
}
enum FunctionType {
suite = 'suite', // Test suite functions (describe, suite, context)
testCase = 'testCase', // Test case functions (it, test, specify)
hook = 'hook' // Hook functions (before, after, beforeEach, afterEach)
}{
"settings": {
"mocha/additionalCustomNames": [
{
"name": "describeModule",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "testModule",
"type": "testCase",
"interfaces": ["TDD"]
}
]
},
"rules": {
"mocha/no-exclusive-tests": "error",
"mocha/no-skipped-tests": "warn"
}
}{
"settings": {
"mocha/additionalCustomNames": [
{
"name": "describe.component",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "it.integration",
"type": "testCase",
"interfaces": ["BDD"]
},
{
"name": "beforeEachComponent",
"type": "hook",
"interfaces": ["BDD"]
}
]
}
}{
"settings": {
"mocha/additionalCustomNames": [
// Ember Mocha extension
{
"name": "describeModule",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "describeComponent",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "describeModel",
"type": "suite",
"interfaces": ["BDD"]
},
// Mocha Each extension
{
"name": "forEach().describe",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "forEach().it",
"type": "testCase",
"interfaces": ["BDD"]
},
// Custom testing utilities
{
"name": "testApi",
"type": "testCase",
"interfaces": ["BDD", "TDD"]
},
{
"name": "setupDatabase",
"type": "hook",
"interfaces": ["BDD", "TDD", "QUnit"]
}
]
}
}// Simple name pattern
{
"name": "describeModule",
"type": "suite",
"interfaces": ["BDD"]
}
// Usage: describeModule("UserModule", function() { ... });
// Dotted name pattern
{
"name": "describe.component",
"type": "suite",
"interfaces": ["BDD"]
}
// Usage: describe.component("Button", function() { ... });
// Function call pattern
{
"name": "forEach().describe",
"type": "suite",
"interfaces": ["BDD"]
}
// Usage: forEach([1, 2, 3]).describe("Numbers", function(n) { ... });
// Complex pattern
{
"name": "forEach().describe.component",
"type": "suite",
"interfaces": ["BDD"]
}
// Usage: forEach(components).describe.component("Component", function(comp) { ... });// ESLint configuration showing how settings affect rule behavior
const config = {
settings: {
'mocha/additionalCustomNames': [
{
name: 'customTest',
type: 'testCase',
interfaces: ['BDD']
},
{
name: 'customDescribe',
type: 'suite',
interfaces: ['BDD']
}
]
},
rules: {
// These rules will now recognize customTest and customDescribe
'mocha/no-exclusive-tests': 'error', // Catches customTest.only
'mocha/no-skipped-tests': 'warn', // Catches customTest.skip
'mocha/no-nested-tests': 'error', // Catches nested customTest
'mocha/no-identical-title': 'error', // Checks customTest titles
'mocha/valid-test-description': 'error' // Validates customTest descriptions
}
};{
"settings": {
"mocha/additionalCustomNames": [
// React Testing Library integration
{
"name": "describeComponent",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "itRendersCorrectly",
"type": "testCase",
"interfaces": ["BDD"]
},
// API Testing utilities
{
"name": "describeEndpoint",
"type": "suite",
"interfaces": ["BDD"]
},
{
"name": "testRequest",
"type": "testCase",
"interfaces": ["BDD", "TDD"]
},
// Database testing
{
"name": "withTransaction",
"type": "hook",
"interfaces": ["BDD", "TDD", "QUnit"]
},
{
"name": "describeModel",
"type": "suite",
"interfaces": ["BDD"]
}
]
},
"rules": {
"mocha/no-exclusive-tests": "error",
"mocha/no-skipped-tests": "warn",
"mocha/no-identical-title": "error",
"mocha/no-empty-description": "error",
"mocha/consistent-spacing-between-blocks": "error"
}
}// Example of how settings are processed internally
function validateCustomName(customName) {
const validTypes = ['suite', 'testCase', 'hook'];
const validInterfaces = ['BDD', 'TDD', 'QUnit'];
if (!customName.name || typeof customName.name !== 'string') {
throw new Error('Custom name must have a string "name" property');
}
if (!validTypes.includes(customName.type)) {
throw new Error(`Custom name type must be one of: ${validTypes.join(', ')}`);
}
if (!Array.isArray(customName.interfaces) ||
!customName.interfaces.every(i => validInterfaces.includes(i))) {
throw new Error(`Custom name interfaces must be array of: ${validInterfaces.join(', ')}`);
}
return true;
}