Rules that enforce proper code organization within test suites to maintain clean, maintainable, and reliable test code.
Prevents variable declarations within describe blocks to maintain proper test isolation and avoid shared mutable state.
/**
* Rule: no-describe-variables
* Disallows variable declarations in describe blocks
* @config [0|1|2] - Rule severity level
*/
'jasmine/no-describe-variables': [0|1|2]Examples:
// ❌ Bad - variables in describe block
describe('User service', function() {
let user = createUser(); // Shared mutable state
let config = { timeout: 5000 }; // Could cause test interdependencies
it('should validate user', function() {
user.name = 'Modified'; // Affects other tests
expect(validateUser(user)).toBe(true);
});
});
// ✅ Good - variables in beforeEach
describe('User service', function() {
let user, config;
beforeEach(function() {
user = createUser(); // Fresh instance for each test
config = { timeout: 5000 }; // Isolated configuration
});
it('should validate user', function() {
user.name = 'Modified'; // Won't affect other tests
expect(validateUser(user)).toBe(true);
});
});Prevents the use of callback arguments (like done) in suite callbacks (describe), which is invalid and can cause test failures.
/**
* Rule: no-suite-callback-args
* Disallows callback arguments in describe blocks
* @config [0|1|2] - Rule severity level
*/
'jasmine/no-suite-callback-args': [0|1|2]Examples:
// ❌ Bad - done callback in describe
describe('Async suite', function(done) { // Invalid - describe doesn't support done
// This will cause test failures
});
// ❌ Bad - any callback args in describe
describe('Suite with args', function(callback, next) { // Invalid
// describe blocks don't accept callback parameters
});
// ✅ Good - no arguments in describe
describe('Async suite', function() {
// Use beforeEach/afterEach for async setup
beforeEach(function(done) {
setupAsync(done);
});
it('should handle async test', function(done) {
performAsyncAction(done);
});
});Prevents global setup and teardown code that can cause test interdependencies and make tests harder to debug.
/**
* Rule: no-global-setup
* Disallows global setup/teardown outside describe blocks
* @config [0|1|2] - Rule severity level
*/
'jasmine/no-global-setup': [0|1|2]Examples:
// ❌ Bad - global setup
beforeEach(function() { // Global beforeEach affects all tests
globalSetup();
});
afterEach(function() { // Global afterEach affects all tests
globalCleanup();
});
describe('Some tests', function() {
it('test 1', function() { /* ... */ });
});
// ✅ Good - scoped setup
describe('Feature tests', function() {
beforeEach(function() { // Scoped to this describe block
featureSetup();
});
afterEach(function() { // Scoped to this describe block
featureCleanup();
});
it('should work correctly', function() { /* ... */ });
});Prevents expectation calls in setup and teardown methods to keep test structure clean and ensure proper test isolation.
/**
* Rule: no-expect-in-setup-teardown
* Disallows expect() calls in beforeEach/afterEach blocks
* @config [0|1|2, ...expectationFunctions] - Rule severity and custom expectation function names
* @default expectationFunctions ['expect()', 'expectAsync()']
*/
'jasmine/no-expect-in-setup-teardown': [0|1|2, 'expect()', 'expectAsync()']Configuration Examples:
// Default configuration
'jasmine/no-expect-in-setup-teardown': 1
// Custom expectation functions
'jasmine/no-expect-in-setup-teardown': [1, 'expect()', 'expectAsync()', 'customExpect()']Examples:
// ❌ Bad - expectations in setup/teardown
describe('Service tests', function() {
beforeEach(function() {
const service = createService();
expect(service).toBeDefined(); // Should not test in setup
});
afterEach(function() {
cleanupService();
expect(cleanupComplete()).toBe(true); // Should not test in cleanup
});
});
// ✅ Good - setup without expectations
describe('Service tests', function() {
let service;
beforeEach(function() {
service = createService(); // Pure setup
});
afterEach(function() {
cleanupService(); // Pure cleanup
});
it('should create service correctly', function() {
expect(service).toBeDefined(); // Test in actual spec
expect(service.isReady()).toBe(true);
});
it('should clean up properly', function() {
service.performAction();
// Test cleanup effects in separate spec if needed
});
});All code organization rules support standard ESLint severity levels:
0 or "off" - Disable the rule1 or "warn" - Enable as warning2 or "error" - Enable as error (fails lint)Recommended Settings:
rules:
jasmine/no-describe-variables: 0 # Optional - some patterns are valid
jasmine/no-suite-callback-args: 2 # Error - invalid Jasmine syntax
jasmine/no-global-setup: 2 # Error - causes test interdependencies
jasmine/no-expect-in-setup-teardown: 1 # Warning - keeps tests cleandescribe('UserService', function() {
let userService, mockDatabase, testUsers;
beforeEach(function() {
// Pure setup - no expectations
mockDatabase = jasmine.createSpyObj('database', ['save', 'find', 'delete']);
userService = new UserService(mockDatabase);
testUsers = [
{ id: 1, name: 'Alice', email: 'alice@test.com' },
{ id: 2, name: 'Bob', email: 'bob@test.com' }
];
});
afterEach(function() {
// Pure cleanup - no expectations
userService = null;
mockDatabase = null;
testUsers = null;
});
describe('save', function() {
it('should save valid user', function() {
const user = testUsers[0];
mockDatabase.save.and.returnValue(user);
const result = userService.save(user);
expect(mockDatabase.save).toHaveBeenCalledWith(user);
expect(result).toEqual(user);
});
it('should validate user before saving', function() {
const invalidUser = { name: '', email: 'invalid' };
expect(function() {
userService.save(invalidUser);
}).toThrow();
expect(mockDatabase.save).not.toHaveBeenCalled();
});
});
describe('find', function() {
it('should find user by id', function() {
const expectedUser = testUsers[0];
mockDatabase.find.and.returnValue(expectedUser);
const result = userService.find(1);
expect(mockDatabase.find).toHaveBeenCalledWith(1);
expect(result).toEqual(expectedUser);
});
});
});// ❌ Avoid - shared mutable state
describe('Calculator', function() {
let result = 0; // This can cause test interdependencies
it('should add', function() {
result = calculator.add(2, 3);
expect(result).toBe(5);
});
it('should multiply', function() {
result = calculator.multiply(result, 2); // Depends on previous test!
expect(result).toBe(10);
});
});
// ✅ Good - isolated tests
describe('Calculator', function() {
it('should add numbers', function() {
const result = calculator.add(2, 3);
expect(result).toBe(5);
});
it('should multiply numbers', function() {
const result = calculator.multiply(5, 2);
expect(result).toBe(10);
});
});