Files
Dawson Blackhouse 91c53144a1 feat: initial commit
2026-01-10 23:40:52 -05:00

9.2 KiB

AngularJS Testing Reference Guide

Frameworks: Jasmine (recommended) and Jest

This reference covers APIs available in both Jasmine and Jest. Most APIs are identical or have direct equivalents.

Jasmine API Reference

Test Structure Functions

Function Purpose Example
describe(name, fn) Group tests into a suite describe('UserController', fn)
it(name, fn) Define a single test it('should initialize', fn)
beforeEach(fn) Run before each test beforeEach(function() { ... })
afterEach(fn) Run after each test afterEach(function() { ... })
beforeAll(fn) Run once before all tests beforeAll(function() { ... })
afterAll(fn) Run once after all tests afterAll(function() { ... })

Expectations (Assertions)

Matcher Purpose Example
toBe() Test exact equality (===) expect(result).toBe(42)
toEqual() Test deep equality expect(obj).toEqual({a: 1})
toMatch() Test regex match expect(text).toMatch(/pattern/)
toBeDefined() Test if defined expect(value).toBeDefined()
toBeUndefined() Test if undefined expect(value).toBeUndefined()
toBeNull() Test if null expect(value).toBeNull()
toBeTruthy() Test truthy value expect(value).toBeTruthy()
toBeFalsy() Test falsy value expect(value).toBeFalsy()
toContain() Test array/string contains expect(arr).toContain(item)
toThrow() Test function throws error expect(fn).toThrow()
toThrowError() Test specific error expect(fn).toThrowError(Error)
toHaveBeenCalled() Test spy was called expect(spy).toHaveBeenCalled()
toHaveBeenCalledWith() Test spy called with args expect(spy).toHaveBeenCalledWith(arg)
toHaveBeenCalledTimes() Test spy call count expect(spy).toHaveBeenCalledTimes(2)
toHaveClass() Test DOM element has class expect(element).toHaveClass('active')

Negation

Add .not before any matcher to negate it:

expect(result).not.toBe(expected);
expect(result).not.toEqual(obj);
expect(result).not.toHaveBeenCalled();

Spies

Creating Spies (Jasmine)

// Spy on existing function
spyOn(object, 'methodName');

// Spy with return value
spyOn(object, 'methodName').and.returnValue('value');

// Spy that calls through to original
spyOn(object, 'methodName').and.callThrough();

// Spy that throws error
spyOn(object, 'methodName').and.throwError('error');

// Spy that calls fake implementation
spyOn(object, 'methodName').and.callFake(function(arg) {
  return arg * 2;
});

// Create standalone spy
var spy = jasmine.createSpy('spyName');
var spy = jasmine.createSpy('spyName').and.returnValue('value');

// Create spy object with multiple methods
var mockObj = jasmine.createSpyObj('mockName', ['method1', 'method2']);

Spy Matchers

// Verify spy was called
expect(spy).toHaveBeenCalled();

// Verify spy was called N times
expect(spy).toHaveBeenCalledTimes(3);

// Verify spy was called with specific arguments
expect(spy).toHaveBeenCalledWith(arg1, arg2);

// Get call info
expect(spy.calls.count()).toBe(2);
expect(spy.calls.argsFor(0)).toEqual([arg1, arg2]);

AngularJS Testing Utilities

Module Loading

// Load module
beforeEach(module('myApp'));

// Load multiple modules
beforeEach(module('myApp', 'ngMock'));

// Configure module before injection
beforeEach(module(function($provide) {
  $provide.value('service', mockService);
}));

Dependency Injection

// Inject dependencies
beforeEach(inject(function($injector) {
  var service = $injector.get('ServiceName');
}));

// Inject with underscore wrapping (recommended)
beforeEach(inject(function(_$httpBackend_, _ServiceName_) {
  $httpBackend = _$httpBackend_;
  service = _ServiceName_;
}));

// Get service directly
var service = inject(function($injector) {
  return $injector.get('ServiceName');
});

$httpBackend

// Expect HTTP method
$httpBackend.expectGET('/api/users');
$httpBackend.expectPOST('/api/users', data);
$httpBackend.expectPUT('/api/users/1', data);
$httpBackend.expectDELETE('/api/users/1');
$httpBackend.expectPATCH('/api/users/1', data);

// Define response
$httpBackend.expectGET('/api/users').respond([users]);
$httpBackend.expectGET('/api/users').respond(200, [users]);
$httpBackend.expectGET('/api/users').respond(500, 'error');

// Match URL patterns
$httpBackend.expectGET(/^\/api\/users\/.+$/).respond([]);

// Flush pending requests
$httpBackend.flush();

// Verify no outstanding requests
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();

$scope Testing

// Create scope
var $scope = $rootScope.$new();

// Apply changes
$scope.name = 'test';
$rootScope.$apply();

// Watch for changes
$scope.$watch('name', function(newVal, oldVal) {
  console.log('Changed:', newVal);
});

// Trigger digest cycle
$rootScope.$digest();

$timeout Testing

// Mock timeout
beforeEach(inject(function(_$timeout_) {
  $timeout = _$timeout_;
}));

// After calling timeout code
$timeout.flush(); // Execute all pending timeouts

// Verify timeout was called
expect($timeout.verifyNoPendingTimers);

Promise Testing

// Inject $q and $rootScope
beforeEach(inject(function(_$q_, _$rootScope_) {
  $q = _$q_;
  $rootScope = _$rootScope_;
}));

// Create deferred object
var deferred = $q.defer();
var promise = deferred.promise;

// Test resolution
promise.then(function(result) {
  expect(result).toBe('success');
});

deferred.resolve('success');
$rootScope.$apply();

// Test rejection
promise.catch(function(error) {
  expect(error).toBe('error');
});

deferred.reject('error');
$rootScope.$apply();

Jest API Reference

Test Structure Functions

Function Purpose Example
describe(name, fn) Group tests into a suite describe('Component', fn)
test(name, fn) Define a single test test('should work', fn)
it(name, fn) Alias for test() it('should work', fn)
beforeEach(fn) Run before each test beforeEach(() => { ... })
afterEach(fn) Run after each test afterEach(() => { ... })
beforeAll(fn) Run once before all tests beforeAll(() => { ... })
afterAll(fn) Run once after all tests afterAll(() => { ... })

Mock Functions

// Create mock function
const mock = jest.fn();

// Mock with return value
const mock = jest.fn().mockReturnValue('value');

// Mock with implementation
const mock = jest.fn((arg) => arg * 2);

// Mock resolved value (Promise)
const mock = jest.fn().mockResolvedValue('success');

// Mock rejected value (Promise)
const mock = jest.fn().mockRejectedValue('error');

// Get call info
expect(mock).toHaveBeenCalled();
expect(mock).toHaveBeenCalledWith(arg);
expect(mock).toHaveBeenCalledTimes(2);
expect(mock.mock.calls[0]).toEqual([arg1, arg2]);

Module Mocking

// Mock entire module
jest.mock('./module');

// Mock with manual implementation
jest.mock('./module', () => ({
  method: jest.fn().mockReturnValue('value')
}));

// Clear mocks
jest.clearAllMocks();
jest.resetAllMocks();

Snapshot Testing

// Create snapshot
expect(component).toMatchSnapshot();

// Update snapshots (--updateSnapshot or -u flag)
jest.updateSnapshot();

Comparison: Jasmine vs Jest

Task Jasmine Jest
Mock function jasmine.createSpy() jest.fn()
Mock module Manual with $provide jest.mock()
HTTP mock $httpBackend jest.mock('axios')
Async test done() callback async/await
Coverage Istanbul plugin Built-in
Snapshots Not supported Supported

Common Patterns

Controller Testing Pattern

describe('MyController', function() {
  var $scope, controller;

  beforeEach(module('myApp'));
  beforeEach(inject(function($controller, $rootScope) {
    $scope = $rootScope.$new();
    controller = $controller('MyController', {
      $scope: $scope
    });
  }));

  it('should initialize', function() {
    expect($scope.property).toBeDefined();
  });
});

Service Testing Pattern

describe('MyService', function() {
  var service, $httpBackend;

  beforeEach(module('myApp'));
  beforeEach(inject(function(_MyService_, _$httpBackend_) {
    service = _MyService_;
    $httpBackend = _$httpBackend_;
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
  });

  it('should fetch data', function() {
    $httpBackend.expectGET('/api/data').respond([]);
    service.getData();
    $httpBackend.flush();
  });
});

Tips & Tricks

  1. Use underscores for injection: _$httpBackend_ prevents variable shadowing
  2. Flush HTTP calls: Always call $httpBackend.flush() after HTTP expectations
  3. Apply changes: Call $rootScope.$apply() to trigger digest cycle
  4. Test async: Use callbacks or promises depending on the service
  5. Mock realistically: Mock services should behave like real services
  6. Isolate tests: Each test should be independent
  7. Group related tests: Use nested describe() blocks

Last Updated: January 10, 2026