ESLint plugin providing 23 linting rules specifically designed for Jasmine testing framework to enforce best practices and catch common mistakes
npx @tessl/cli install tessl/npm-eslint-plugin-jasmine@4.2.0ESLint Plugin Jasmine provides comprehensive linting rules specifically designed for Jasmine testing framework. It includes 23 rules that help enforce best practices in Jasmine test suites, covering areas such as expectation handling, test organization, spy management, and code style consistency.
npm install --save-dev eslint-plugin-jasmineESLint plugin installation and configuration:
# Install the plugin
npm install --save-dev eslint-plugin-jasmine// .eslintrc.js configuration
module.exports = {
plugins: ['jasmine'],
env: {
jasmine: true
},
extends: ['plugin:jasmine/recommended']
};# .eslintrc.yml configuration
plugins:
- jasmine
env:
jasmine: true
extends: 'plugin:jasmine/recommended'// .eslintrc.json configuration
{
"plugins": ["jasmine"],
"env": {
"jasmine": true
},
"extends": ["plugin:jasmine/recommended"]
}# .eslintrc.yml
plugins:
- jasmine
env:
jasmine: true
extends: "plugin:jasmine/recommended"Custom rule configuration:
plugins:
- jasmine
env:
jasmine: true
rules:
jasmine/no-focused-tests: 2
jasmine/expect-matcher: 1
jasmine/no-suite-dupes:
- 2
- branchESLint Plugin Jasmine is built around several key components:
The plugin includes several internal helper functions used by multiple rules for common patterns:
/**
* buildName - Builds a qualified name from AST node
* Converts CallExpression and MemberExpression nodes to string representations
* @param node - AST node to build name from
* @returns string representation (e.g., "expect()" or "describe.only()")
*/
function buildName(node: ASTNode): string;
/**
* getName - Extracts name from AST node
* Handles Identifier, Literal, and MemberExpression nodes
* @param node - AST node to extract name from
* @returns extracted name or null
*/
function getName(node: ASTNode): string | null;
/**
* prohibit - Creates rule listener that prohibits specified function calls
* Generic helper for creating rules that ban certain function names
* @param prohibiteds - Array of prohibited function names
* @param context - ESLint rule context
* @returns ESLint rule listener object
*/
function prohibit(prohibiteds: string[], context: RuleContext): RuleListener;
/**
* noDupes - Creates rule for detecting duplicate suite/spec names
* Configurable helper for duplicate detection in blocks or branches
* @param kind - Type of duplication ('suite' or 'spec')
* @param branchBlocks - Array of branch block types
* @param checkedBlocks - Array of checked block types
* @returns ESLint rule configuration with create function
*/
function noDupes(
kind: string,
branchBlocks: string[],
checkedBlocks: string[]
): ESLintRule;// Main plugin export structure
module.exports = {
rules: {
'expect-matcher': ESLintRule,
'expect-single-argument': ESLintRule,
'missing-expect': ESLintRule,
'named-spy': ESLintRule,
'new-line-before-expect': ESLintRule,
'new-line-between-declarations': ESLintRule,
'no-assign-spyon': ESLintRule,
'no-describe-variables': ESLintRule,
'no-disabled-tests': ESLintRule,
'no-expect-in-setup-teardown': ESLintRule,
'no-focused-tests': ESLintRule,
'no-global-setup': ESLintRule,
'no-pending-tests': ESLintRule,
'no-promise-without-done-fail': ESLintRule,
'no-spec-dupes': ESLintRule,
'no-suite-callback-args': ESLintRule,
'no-suite-dupes': ESLintRule,
'no-unsafe-spy': ESLintRule,
'prefer-jasmine-matcher': ESLintRule,
'prefer-promise-strategies': ESLintRule,
'prefer-toHaveBeenCalledWith': ESLintRule,
'prefer-toBeUndefined': ESLintRule,
'valid-expect': ESLintRule
},
configs: {
recommended: {
rules: {
'jasmine/expect-matcher': 1,
'jasmine/expect-single-argument': 1,
'jasmine/named-spy': 0,
'jasmine/no-focused-tests': 2,
'jasmine/no-disabled-tests': 1,
'jasmine/no-describe-variables': 0,
'jasmine/no-suite-dupes': 1,
'jasmine/no-spec-dupes': 1,
'jasmine/missing-expect': 0,
'jasmine/no-suite-callback-args': 2,
'jasmine/no-assign-spyon': 0,
'jasmine/no-unsafe-spy': 1,
'jasmine/no-global-setup': 2,
'jasmine/no-pending-tests': 1,
'jasmine/no-promise-without-done-fail': 1,
'jasmine/no-expect-in-setup-teardown': 1,
'jasmine/new-line-between-declarations': 1,
'jasmine/new-line-before-expect': 1,
'jasmine/prefer-jasmine-matcher': 1,
'jasmine/prefer-promise-strategies': 1,
'jasmine/prefer-toHaveBeenCalledWith': 1,
'jasmine/prefer-toBeUndefined': 0
}
}
}
}Rules that enforce proper usage of Jasmine's expect() functionality and matchers.
// expect-matcher: Enforce expect having a corresponding matcher
'jasmine/expect-matcher': [0|1|2]
// expect-single-argument: Enforce expect to have a single argument
'jasmine/expect-single-argument': [0|1|2]
// missing-expect: Enforce expects in test cases
'jasmine/missing-expect': [0|1|2, 'expect()', 'expectAsync()']
// valid-expect: Enforce valid expect usage (deprecated)
'jasmine/valid-expect': [0|1|2]Rules that enforce proper test organization and prevent common structural issues.
// no-focused-tests: Disallow focused tests
'jasmine/no-focused-tests': [0|1|2]
// no-disabled-tests: Disallow disabled tests
'jasmine/no-disabled-tests': [0|1|2]
// no-pending-tests: Disallow pending tests
'jasmine/no-pending-tests': [0|1|2]
// no-suite-dupes: Disallow duplicate suite names
'jasmine/no-suite-dupes': [0|1|2, 'block'|'branch']
// no-spec-dupes: Disallow duplicate spec names
'jasmine/no-spec-dupes': [0|1|2, 'block'|'branch']Rules that enforce best practices for Jasmine spy usage and management.
// named-spy: Enforce named spies
'jasmine/named-spy': [0|1|2]
// no-assign-spyon: Disallow assignment to spyOn
'jasmine/no-assign-spyon': [0|1|2]
// no-unsafe-spy: Disallow unsafe spy usage
'jasmine/no-unsafe-spy': [0|1|2]Rules that enforce proper code organization within test suites.
// no-describe-variables: Disallow variable declarations in describe blocks
'jasmine/no-describe-variables': [0|1|2]
// no-suite-callback-args: Disallow arguments in suite callbacks
'jasmine/no-suite-callback-args': [0|1|2]
// no-global-setup: Disallow global setup/teardown
'jasmine/no-global-setup': [0|1|2]
// no-expect-in-setup-teardown: Disallow expects in setup/teardown
'jasmine/no-expect-in-setup-teardown': [0|1|2, 'expect()', 'expectAsync()']Rules that enforce consistent code style and formatting in Jasmine tests.
// new-line-between-declarations: Enforce new lines between declarations
'jasmine/new-line-between-declarations': [0|1|2]
// new-line-before-expect: Enforce new line before expect statements
'jasmine/new-line-before-expect': [0|1|2]Rules that enforce proper handling of promises and asynchronous code in Jasmine tests.
// no-promise-without-done-fail: Disallow promises without done.fail
'jasmine/no-promise-without-done-fail': [0|1|2]
// prefer-promise-strategies: Prefer modern promise strategies
'jasmine/prefer-promise-strategies': [0|1|2]Rules that encourage usage of Jasmine-specific matchers over generic alternatives.
// prefer-jasmine-matcher: Prefer Jasmine matchers over generic ones
'jasmine/prefer-jasmine-matcher': [0|1|2]
// prefer-toHaveBeenCalledWith: Prefer specific spy matcher
'jasmine/prefer-toHaveBeenCalledWith': [0|1|2]
// prefer-toBeUndefined: Prefer toBeUndefined matcher
'jasmine/prefer-toBeUndefined': [0|1|2, 'always'|'never']Jasmine-Specific Matcher Rules
// ESLint rule configuration values
type RuleLevel = 0 | 1 | 2; // 0 = off, 1 = warn, 2 = error
// Rule options for duplicate detection
type DupeMode = 'block' | 'branch';
// Rule options for prefer-toBeUndefined
type PreferenceMode = 'always' | 'never';
// ESLint rule function interface
interface ESLintRule {
meta?: {
schema?: any;
type?: 'problem' | 'suggestion' | 'layout';
docs?: {
description?: string;
category?: string;
recommended?: boolean;
};
fixable?: 'code' | 'whitespace';
messages?: { [key: string]: string };
};
create: (context: RuleContext) => RuleListener;
}
// ESLint rule context interface
interface RuleContext {
options: any[];
getAncestors?: () => ASTNode[];
sourceCode?: {
getAncestors: (node: ASTNode) => ASTNode[];
};
report: (descriptor: ReportDescriptor) => void;
}
// ESLint rule listener interface
interface RuleListener {
[key: string]: (node: ASTNode) => void;
}
// ESLint AST node interface
interface ASTNode {
type: string;
parent?: ASTNode;
callee?: {
name?: string;
};
arguments?: ASTNode[];
}
// Report descriptor interface
interface ReportDescriptor {
message: string;
node: ASTNode;
fix?: (fixer: RuleFixer) => FixResult;
}
// Rule fixer interface
interface RuleFixer {
insertTextAfter: (nodeOrToken: ASTNode, text: string) => FixResult;
insertTextBefore: (nodeOrToken: ASTNode, text: string) => FixResult;
remove: (nodeOrToken: ASTNode) => FixResult;
replaceText: (nodeOrToken: ASTNode, text: string) => FixResult;
}
// Fix result interface
interface FixResult {
range: [number, number];
text: string;
}
// Configuration object structure
interface PluginConfig {
rules: {
[ruleName: string]: RuleLevel | [RuleLevel, ...any[]];
};
}
// Plugin structure
interface ESLintPlugin {
rules: { [ruleName: string]: ESLintRule };
configs: { [configName: string]: PluginConfig };
}
// Recommended configuration preset
interface RecommendedConfig {
rules: {
'jasmine/expect-matcher': 1;
'jasmine/expect-single-argument': 1;
'jasmine/named-spy': 0;
'jasmine/no-focused-tests': 2;
'jasmine/no-disabled-tests': 1;
'jasmine/no-describe-variables': 0;
'jasmine/no-suite-dupes': 1;
'jasmine/no-spec-dupes': 1;
'jasmine/missing-expect': 0;
'jasmine/no-suite-callback-args': 2;
'jasmine/no-assign-spyon': 0;
'jasmine/no-unsafe-spy': 1;
'jasmine/no-global-setup': 2;
'jasmine/no-pending-tests': 1;
'jasmine/no-promise-without-done-fail': 1;
'jasmine/no-expect-in-setup-teardown': 1;
'jasmine/new-line-between-declarations': 1;
'jasmine/new-line-before-expect': 1;
'jasmine/prefer-jasmine-matcher': 1;
'jasmine/prefer-promise-strategies': 1;
'jasmine/prefer-toHaveBeenCalledWith': 1;
'jasmine/prefer-toBeUndefined': 0;
};
}