or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

code-organization-rules.mdcode-style-rules.mdexpectation-rules.mdindex.mdjasmine-matcher-rules.mdpromise-rules.mdspy-rules.mdtest-structure-rules.md
tile.json

code-style-rules.mddocs/

Code Style Rules

Rules that enforce consistent code style and formatting in Jasmine tests to improve readability and maintainability.

Capabilities

new-line-between-declarations

Enforces new lines between variable declarations in test files to improve readability and make code structure clearer.

/**
 * Rule: new-line-between-declarations
 * Enforces new lines between variable declarations
 * @config [0|1|2] - Rule severity level
 */
'jasmine/new-line-between-declarations': [0|1|2]

Examples:

// ❌ Bad - declarations without spacing
describe('Service tests', function() {
  let service;
  let config;
  let mockData;
  
  beforeEach(function() {
    let options = {};
    let settings = getSettings();
    let environment = 'test';
    // Hard to scan visually
  });
});

// ✅ Good - spaced declarations
describe('Service tests', function() {
  let service;
  
  let config;
  
  let mockData;
  
  beforeEach(function() {
    let options = {};
    
    let settings = getSettings();
    
    let environment = 'test';
    // Much clearer visual separation
  });
});

new-line-before-expect

Enforces a new line before expect statements to visually separate test setup from assertions and improve test readability.

/**
 * Rule: new-line-before-expect
 * Enforces new line before expect statements for better readability
 * @config [0|1|2] - Rule severity level
 */
'jasmine/new-line-before-expect': [0|1|2]

Examples:

// ❌ Bad - no space before expect
it('should calculate total', function() {
  const items = [{ price: 10 }, { price: 20 }];
  const service = new PriceService();
  const result = service.calculateTotal(items);
  expect(result).toBe(30);
});

// ❌ Bad - multiple expects without spacing
it('should validate user data', function() {
  const user = { name: 'John', age: 30 };
  const validator = new UserValidator();
  const result = validator.validate(user);
  expect(result.isValid).toBe(true);
  expect(result.errors).toEqual([]);
  expect(user.name).toBe('John');
});

// ✅ Good - proper spacing before expects
it('should calculate total', function() {
  const items = [{ price: 10 }, { price: 20 }];
  const service = new PriceService();
  const result = service.calculateTotal(items);
  
  expect(result).toBe(30);
});

// ✅ Good - spaced expects for better readability
it('should validate user data', function() {
  const user = { name: 'John', age: 30 };
  const validator = new UserValidator();
  const result = validator.validate(user);
  
  expect(result.isValid).toBe(true);
  expect(result.errors).toEqual([]);
  expect(user.name).toBe('John');
});

Rule Configuration

Both code style 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/new-line-between-declarations: 1   # Warning - improves readability
  jasmine/new-line-before-expect: 1          # Warning - separates setup from assertions

Style Guidelines

Readable Test Structure

describe('UserRegistrationService', function() {
  let service;
  
  let mockEmailService;
  
  let mockDatabase;
  
  let validUserData;
  
  beforeEach(function() {
    mockEmailService = jasmine.createSpyObj('emailService', ['sendWelcome']);
    
    mockDatabase = jasmine.createSpyObj('database', ['save', 'findByEmail']);
    
    service = new UserRegistrationService(mockEmailService, mockDatabase);
    
    validUserData = {
      name: 'John Doe',
      email: 'john@example.com',
      password: 'securePassword123'
    };
  });
  
  describe('registerUser', function() {
    it('should register new user successfully', function() {
      mockDatabase.findByEmail.and.returnValue(null);
      mockDatabase.save.and.returnValue({ id: 123, ...validUserData });
      
      const result = service.registerUser(validUserData);
      
      expect(mockDatabase.findByEmail).toHaveBeenCalledWith('john@example.com');
      expect(mockDatabase.save).toHaveBeenCalledWith(validUserData);
      expect(mockEmailService.sendWelcome).toHaveBeenCalledWith(validUserData.email);
      expect(result.success).toBe(true);
      expect(result.user.id).toBe(123);
    });
    
    it('should reject duplicate email addresses', function() {
      const existingUser = { id: 456, email: 'john@example.com' };
      mockDatabase.findByEmail.and.returnValue(existingUser);
      
      const result = service.registerUser(validUserData);
      
      expect(mockDatabase.findByEmail).toHaveBeenCalledWith('john@example.com');
      expect(mockDatabase.save).not.toHaveBeenCalled();
      expect(mockEmailService.sendWelcome).not.toHaveBeenCalled();
      expect(result.success).toBe(false);
      expect(result.error).toBe('Email already registered');
    });
    
    it('should validate required fields', function() {
      const invalidData = { name: '', email: 'invalid-email', password: '123' };
      
      const result = service.registerUser(invalidData);
      
      expect(result.success).toBe(false);
      expect(result.errors).toContain('Name is required');
      expect(result.errors).toContain('Invalid email format');
      expect(result.errors).toContain('Password too short');
    });
  });
});

Complex Test Scenarios

describe('DataProcessingPipeline', function() {
  let pipeline;
  
  let mockValidator;
  
  let mockTransformer;
  
  let mockStorage;
  
  let sampleData;
  
  beforeEach(function() {
    mockValidator = jasmine.createSpyObj('validator', ['validate']);
    
    mockTransformer = jasmine.createSpyObj('transformer', ['transform']);
    
    mockStorage = jasmine.createSpyObj('storage', ['save']);
    
    pipeline = new DataProcessingPipeline(mockValidator, mockTransformer, mockStorage);
    
    sampleData = [
      { id: 1, name: 'Item 1', value: 100 },
      { id: 2, name: 'Item 2', value: 200 },
      { id: 3, name: 'Item 3', value: 300 }
    ];
  });
  
  describe('processData', function() {
    it('should process valid data through complete pipeline', async function() {
      const validatedData = sampleData.map(item => ({ ...item, validated: true }));
      const transformedData = validatedData.map(item => ({ ...item, processed: true }));
      
      mockValidator.validate.and.returnValue(Promise.resolve(validatedData));
      mockTransformer.transform.and.returnValue(Promise.resolve(transformedData));
      mockStorage.save.and.returnValue(Promise.resolve({ success: true }));
      
      const result = await pipeline.processData(sampleData);
      
      expect(mockValidator.validate).toHaveBeenCalledWith(sampleData);
      expect(mockTransformer.transform).toHaveBeenCalledWith(validatedData);
      expect(mockStorage.save).toHaveBeenCalledWith(transformedData);
      expect(result.success).toBe(true);
      expect(result.processedCount).toBe(3);
    });
    
    it('should handle validation errors gracefully', async function() {
      const validationError = new Error('Validation failed for item 2');
      mockValidator.validate.and.returnValue(Promise.reject(validationError));
      
      const result = await pipeline.processData(sampleData);
      
      expect(mockValidator.validate).toHaveBeenCalledWith(sampleData);
      expect(mockTransformer.transform).not.toHaveBeenCalled();
      expect(mockStorage.save).not.toHaveBeenCalled();
      expect(result.success).toBe(false);
      expect(result.error).toBe('Validation failed for item 2');
    });
  });
});

Benefits of Consistent Styling

Improved Readability

  • Clear visual separation between setup, action, and assertion phases
  • Easier to scan and understand test structure
  • Consistent formatting across team members

Better Maintenance

  • Easier to locate specific parts of tests
  • Clearer boundaries between different test concerns
  • Reduced cognitive load when reading tests

Enhanced Debugging

  • Clear visual structure helps identify issues faster
  • Proper spacing makes it easier to add debug statements
  • Consistent patterns make tests more predictable