October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

AngularJS Testing Tips: How to Test Directives Through Compilation and Linking

A practical legacy AngularJS guide to testing directives through $compile and scope linking, with event assertions and $httpBackend examples.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test an AngularJS directive through the same compilation and linking path that runs in the application: load its module, compile representative markup with $compile, link it to the scope arrangement the directive expects, then assert the rendered DOM, bindings and interactions it promises. Add angular-mocks.js for ngMock helpers, and use $httpBackend when the directive initiates HTTP requests.

Decide what the directive must prove

A directive test is strongest when it describes an observable contract rather than its private implementation. AngularJS directives can attach behavior to an element, listen for events, or transform the element and its children. Choose the behavior a user or parent component relies on before writing the test.

  • Rendering: expected text, attributes, classes, child elements or visibility.
  • Binding: whether an input, output or watched value moves correctly between the directive and its scope.
  • Interaction: what a click, input, keyboard event or other listener does.
  • Requirements: behavior when a required attribute, controller or binding is present or missing.
  • Collaboration: the result of a service call, including the directive’s response to success or failure.

Keep assertions at the DOM and interaction boundary whenever possible. A directive that directly accesses the DOM is difficult to test if that access is spread through unrelated application code; keeping DOM-specific behavior in the directive gives the test a clear place to exercise it.

Build the AngularJS test context

Include the AngularJS test support file, normally angular-mocks.js, after AngularJS and before the test suite. It provides the ngMock module and helpers such as module() and inject(). Load the application module that registers the directive before each relevant suite or test.

describe('statusBadge directive', function () {
  beforeEach(module('billingApp'));

  var $compile, $rootScope;

  beforeEach(inject(function (_$compile_, _$rootScope_) {
    $compile = _$compile_;
    $rootScope = _$rootScope_;
  }));

  // tests go here
});

The exact runner configuration varies by project and AngularJS version, so use the dependency versions already installed in the legacy application. The AngularJS API documentation identifies a 1.8.4 snapshot and records that official support ended in January 2022; treat this workflow as maintenance guidance and verify local tooling before changing it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Compile representative markup and link it to a scope

$compile matches directives in a template and creates a template function. Linking applies that function to a scope, evaluates bindings and produces the live DOM that the test can inspect. Compile the markup a real caller would use instead of instantiating the directive’s factory in isolation.

it('renders the current status', function () {
  var scope = $rootScope.$new();
  scope.invoice = { status: 'Paid' };

  var element = $compile(
    '<status-badge status="invoice.status"></status-badge>'
  )(scope);

  scope.$digest();

  expect(element.text()).toContain('Paid');
});

Use a child scope or the scope created by the directive according to its definition. An inherited-scope directive, an isolate-scope directive and a directive using bindToController receive data differently. The test should reproduce that arrangement, including parent properties and attributes, rather than assigning values directly to an internal object.

Check bindings after a digest

AngularJS watchers update during a digest. Set initial state, compile and link, then run the digest needed for bindings to settle. Change the state and digest again when testing a watched value.

it('updates when the watched value changes', function () {
  var scope = $rootScope.$new();
  scope.label = 'Queued';
  var element = $compile('<status-badge label="label"></status-badge>')(scope);

  scope.$digest();
  expect(element.text()).toContain('Queued');

  scope.label = 'Sent';
  scope.$digest();
  expect(element.text()).toContain('Sent');
});

Assert the contract a consumer can observe: text, structure, classes, attributes, emitted callbacks or changed model values. Avoid asserting the number or order of private watchers unless that implementation detail is itself part of the supported behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Exercise event listeners and user interactions

Listener directives register DOM handlers. Trigger the same event a user would cause and assert the resulting behavior, such as a callback, class change or model update.

it('calls the supplied callback on click', function () {
  var scope = $rootScope.$new();
  scope.onChoose = jasmine.createSpy('onChoose');
  var element = $compile(
    '<pick-row on-choose="onChoose(item)" item="row"></pick-row>'
  )(scope);

  scope.row = { id: 7 };
  scope.$digest();
  element.triggerHandler('click');

  expect(scope.onChoose).toHaveBeenCalledWith(scope.row);
});

Use the event API appropriate to the test environment and directive. If the handler schedules a scope change, run a digest afterward before checking the DOM. Test meaningful branches separately: disabled controls should not invoke the callback, invalid input should show the documented state, and repeated events should not create duplicate effects.

Rank #4
AngularJS
  • Used Book in Good Condition

Mock HTTP instead of using a live network

When a directive calls $http, configure an $httpBackend expectation before triggering the behavior. Invoke the action, flush the trained response, then assert the directive’s visible result. This keeps the test deterministic and verifies both the request and the response handling.

beforeEach(inject(function (_$httpBackend_) {
  $httpBackend = _$httpBackend_;
}));

it('renders data returned by the service', function () {
  var scope = $rootScope.$new();
  var element = $compile('<account-summary account-id="42"></account-summary>')(scope);

  $httpBackend.expectGET('/api/accounts/42').respond(200, {
    name: 'Northwind'
  });

  scope.$digest();
  $httpBackend.flush();
  scope.$digest();

  expect(element.text()).toContain('Northwind');
});

Add expectations for failure responses when the directive exposes an error state. A test that never calls $httpBackend.flush() has not processed the pending request and cannot prove the post-response behavior. Verify that unexpected requests fail the test and that each expected request is satisfied.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A practical directive-test checklist

  1. Write down the visible or interactive contract.
  2. Load angular-mocks.js and the application’s directive module.
  3. Create the parent or isolate scope arrangement used by the directive.
  4. Compile the markup a real consumer supplies with $compile.
  5. Link it to the scope and run the required digest.
  6. Assert DOM output, bindings and callbacks.
  7. Trigger representative DOM events and assert their effects.
  8. For HTTP behavior, set $httpBackend expectations, trigger the action, flush, and test success and error outcomes.
  9. Keep each test focused on one contract and avoid private implementation details.

Common failures and how to diagnose them

The element is empty or the directive never runs

Check that the correct application module is loaded, the directive name and markup match, and the compiled element is linked to the intended scope. A missing digest can also leave bindings unapplied.

Bindings stay undefined

Confirm that the test supplies every required attribute and uses the correct parent property. Isolate-scope bindings do not automatically behave like inherited-scope properties.

An event assertion fails

Trigger the event on the element that actually owns the listener, then run a digest if the handler changes scope-backed output. Also test the directive’s disabled or guard conditions.

The HTTP test hangs or reports outstanding requests

Set the request expectation before the action that starts the request, call $httpBackend.flush(), and verify the URL and method exactly. Unexpected or unflushed requests indicate that the test’s setup does not match the directive’s network behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Working safely in a legacy AngularJS codebase

AngularJS official support ended in January 2022. Existing applications can still be maintained with this compile-and-link approach, but the browser, test runner, AngularJS package and angular-mocks.js version must remain compatible with one another. Record the versions used by the project, avoid assuming that a modern runner supports an old configuration unchanged, and run the suite in the same environment used by the application build.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.