CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-eslint-plugin-jasmine

ESLint plugin providing 23 linting rules specifically designed for Jasmine testing framework to enforce best practices and catch common mistakes

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

code-organization-rules.mddocs/

Code Organization Rules

Rules that enforce proper code organization within test suites to maintain clean, maintainable, and reliable test code.

Capabilities

no-describe-variables

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);
  });
});

no-suite-callback-args

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);
  });
});

no-global-setup

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() { /* ... */ });
});

no-expect-in-setup-teardown

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
  });
});

Rule Configuration

All code organization rules support standard ESLint severity levels:

  • 0 or "off" - Disable the rule
  • 1 or "warn" - Enable as warning
  • 2 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 clean

Best Practices

Proper Test Organization

describe('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);
    });
  });
});

Avoiding Common Pitfalls

// ❌ 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);
  });
});

docs

code-organization-rules.md

code-style-rules.md

expectation-rules.md

index.md

jasmine-matcher-rules.md

promise-rules.md

spy-rules.md

test-structure-rules.md

tile.json