angularjs-unit-testing
Use this skill for AngularJS unit testing, maintenance, and migration tasks
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Use this skill for AngularJS unit testing, maintenance, and migration tasks
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Guides an autonomous blog manager agent to propose topics, draft articles, and skip topics with structured JSON output for a Leaflet.pub publication.
Design and build AI agents with persistent memory, tool use, and multi-turn conversation. Covers architecture selection, memory design, model selection, tool configuration, and implementation patterns across agent frameworks. Use when creating, debugging, or improving AI agents.
Automate configuration management and application deployment with Ansible. Use when tasks mention ansible-playbook, inventory files, Ansible roles, ad-hoc commands, ansible-galaxy, or agentless SSH automation.
Deploy Kubernetes apps declaratively with Argo CD applications and projects. Use when tasks mention argocd, Argo CD, argocd app sync, Application CRD, AppProject, or GitOps with Argo CD.
Query Datadog observability data including logs, metrics, monitors, dashboards, hosts, APM spans, and incidents via direct API. Use when investigating production issues, checking monitors, searching logs, alerting, or accessing Datadog data.
Build, run, debug, and manage Docker containers, images, compose files, networking, volumes, registries, Buildx/Bake, Scout/SBOM, Swarm, and Docker AI tooling. Use when the user mentions docker, containers, containerizing, Dockerfile, compose, image registry, volumes, or any docker subcommand.
| name | angularjs-unit-testing |
| description | Use this skill for AngularJS unit testing, maintenance, and migration tasks |
This skill specializes in writing, refactoring, and maintaining high-quality unit tests for AngularJS (1.x) applications. It covers controllers, services, filters, directives, HTTP mocking, promises, and dependency injection — everything you need to keep an AngularJS codebase well-tested and reliable.
Note: AngularJS reached end-of-life in December 2021. It receives only critical security fixes. New projects should use Angular 19+. For teams maintaining AngularJS codebases, this skill provides the latest testing patterns, tooling, and migration guidance. See Migration Path at the bottom of this document.
$httpBackend (Jasmine/Karma) or MSW/fetch mocks (Jest)$q, deferred objects, and $timeoutThis skill implements the following testing patterns:
AAA Pattern (Arrange-Act-Assert)
Mocking & Spying
Test Fixtures
Edge Case Testing
Snapshot Testing (Jest)
Deterministic Async
Jasmine remains the safest choice when you are preserving an existing AngularJS + Karma suite.
Key Concepts:
describe(): Group related tests into a test suiteit(): Define individual test casesexpect(): Create assertionsbeforeEach() / afterEach(): Setup and teardown hooksspyOn() / jasmine.createSpy(): Mock functions and track callsSetup:
npm install --save-dev jasmine karma karma-jasmine karma-chrome-launcher
Use when:
Jest is the modern default for AngularJS test maintenance and migration work. It runs tests in parallel, has stronger mocking APIs, supports snapshots, and includes built-in coverage reporting.
Key Concepts:
describe(): Group related teststest() or it(): Define individual test casesexpect(): Create assertionsbeforeEach() / afterEach(): Setup and teardown hooksjest.fn(): Create mock functionsjest.spyOn(): Spy on existing methodsjest.mock(): Mock modulesSetup:
npm install --save-dev jest jest-preset-angular angular-mocks
npm install @angular/core
Jest Configuration (jest.config.js):
module.exports = {
preset: 'jest-preset-angular',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/setup-jest.js'],
transform: {
'^.+\.js$': 'babel-jest'
},
collectCoverage: true,
collectCoverageFrom: ['src/**/*.js', '!src/**/*.spec.js']
};
Use when:
Karma is the legacy browser test runner traditionally paired with Jasmine. It is still usable for existing suites, but it has seen no major releases since 2021 and should not be the basis for new investment.
Configuration:
karma.conf.js: Main configuration fileUse these steps when moving an AngularJS test suite from Jasmine/Karma to Jest:
Install the core tooling
npm install --save-dev jest jest-preset-angular angular-mocks
npm install @angular/core
Add @angular/core when the repo is hybrid or actively migrating toward Angular.
Create a Jest setup file
setup-jest.js or setup-jest.tsangular, angular-mocks, and any shared test polyfills thereConfigure Jest for AngularJS files
jest.config.js with testEnvironment: 'jsdom'Load AngularJS modules in Jest
beforeEach(() => {
require('angular');
require('angular-mocks');
angular.mock.module('myApp');
});
Migrate spies and stubs
spyOn(obj, 'method') → jest.spyOn(obj, 'method')jasmine.createSpy() → jest.fn()jasmine.createSpyObj() → jest.fn() or explicit mock objectsReplace $httpBackend where practical
fetch mocks or MSW for new Jest tests$httpBackend only for legacy tests that are expensive to rewrite immediatelyReset state between tests
jest.clearAllMocks() / jest.resetAllMocks()beforeEach()Legacy AngularJS suites often fail because the environment is unstable, not because the code is broken.
Common sources of flakiness:
Deterministic test patterns:
afterEach()js-env-sanitizer pattern:
window, document, localStorage, Date, Math.random, feature flags, and DOM mutationsLegacy AngularJS codebases often have an inverted test pyramid: too many end-to-end tests and too few unit tests.
Recommended shape:
Guidance:
All Jasmine tests follow this standard structure:
describe('Component Name', function() {
var componentUnderTest, dependencies;
beforeEach(module('myApp'));
beforeEach(inject(function($injector) {
componentUnderTest = $injector.get('ComponentName');
dependencies = $injector.get('DependencyName');
}));
afterEach(function() {
// Cleanup code
});
describe('Functionality Group', function() {
it('should do something specific', function() {
// Arrange
var input = 'test';
// Act
var result = componentUnderTest.method(input);
// Assert
expect(result).toBe('expected');
});
});
});
Jest tests follow a similar structure with modern mocking and cleaner teardown:
describe('Component Name', () => {
let componentUnderTest;
let dependency;
beforeEach(() => {
jest.clearAllMocks();
// Setup code or mock initialization
dependency = { method: jest.fn() };
componentUnderTest = require('./component');
});
afterEach(() => {
// Cleanup code
});
describe('Functionality Group', () => {
test('should do something specific', () => {
// Arrange
const input = 'test';
// Act
const result = componentUnderTest.method(input, dependency);
// Assert
expect(result).toBe('expected');
});
});
});
Key Differences:
jest.fn() / jest.spyOn() instead of Jasmine spies for modern test codetest() or it() (both work).spec.js and .test.js filescontroller.spec.js for controller.js)describe()beforeEach() blocksafterEach()describe('UserController', function() {
var $scope, controller;
beforeEach(module('myApp'));
beforeEach(inject(function($controller, $rootScope) {
$scope = $rootScope.$new();
controller = $controller('UserController', {
$scope: $scope
});
}));
it('should initialize with default values', function() {
expect($scope.users).toBeDefined();
});
it('should load users on init', function() {
expect($scope.users.length).toBeGreaterThan(0);
});
});
describe('UserService', function() {
var userService, $httpBackend;
beforeEach(module('myApp'));
beforeEach(inject(function(_UserService_, _$httpBackend_) {
userService = _UserService_;
$httpBackend = _$httpBackend_;
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
});
it('should fetch users from API', function() {
var expectedUsers = [{ id: 1, name: 'John' }];
$httpBackend.expectGET('/api/users').respond(expectedUsers);
userService.getUsers().then(function(users) {
expect(users).toEqual(expectedUsers);
});
$httpBackend.flush();
});
});
describe('PromiseService', function() {
var service, $q, $rootScope;
beforeEach(inject(function(_Service_, _$q_, _$rootScope_) {
service = _Service_;
$q = _$q_;
$rootScope = _$rootScope_;
}));
it('should handle promise resolution', function() {
var deferred = $q.defer();
var result;
service.asyncOperation().then(function(data) {
result = data;
});
deferred.resolve('success');
$rootScope.$apply();
expect(result).toBe('success');
});
});
AngularJS 1.5+ component directives (bindings, controllerAs) are the recommended pattern for new code and the easiest to migrate to Angular later.
describe('userCard component', function() {
var $compile, $rootScope, element, scope;
beforeEach(module('myApp'));
beforeEach(inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
scope = $rootScope.$new();
scope.user = { name: 'Alice', role: 'admin' };
}));
it('should render user name and role', function() {
element = $compile('<user-card user="user"></user-card>')(scope);
scope.$digest();
var isolated = element.isolateScope().$ctrl;
expect(isolated.user.name).toBe('Alice');
expect(element.text()).toContain('admin');
});
it('should call onSelect when clicked', function() {
scope.onSelect = jasmine.createSpy('onSelect');
element = $compile('<user-card user="user" on-select="onSelect(user)"></user-card>')(scope);
scope.$digest();
element.isolateScope().$ctrl.onSelect({ user: scope.user });
expect(scope.onSelect).toHaveBeenCalledWith(scope.user);
});
});
For APIs with dynamic segments or query parameters, use regex or function matchers instead of exact URL strings:
// Match any GET to /api/users with query params
$httpBackend.expectGET(/\/api\/users\?.*page=/).respond(200, mockResponse);
// Match by function
$httpBackend.expectGET(function(url) {
return url.indexOf('/api/users') === 0 && url.indexOf('page=') > -1;
}).respond(200, mockResponse);
describe('event-driven service', function() {
var $rootScope, service;
beforeEach(inject(function(_$rootScope_, _EventService_) {
$rootScope = _$rootScope_;
service = _EventService_;
}));
it('should react to user:updated event', function() {
var handler = jasmine.createSpy('handler');
$rootScope.$on('user:updated', handler);
$rootScope.$broadcast('user:updated', { id: 42 });
expect(handler).toHaveBeenCalled();
expect(handler.calls.argsFor(0)[1]).toEqual({ id: 42 });
});
});
// Skip a test
xit('should do something', function() { ... });
// Run only this test
fit('should do something', function() { ... });
// Console logging in tests
it('should debug', function() {
console.log('Current state:', $scope);
expect(true).toBe(true);
});
// Skip a test
test.skip('should do something', () => { ... });
// Run only this test
test.only('should do something', () => { ... });
// Debug with Node inspector
// Run: node --inspect-brk node_modules/.bin/jest --runInBand
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
- run: npm ci
- run: npm test -- --coverage
- uses: codecov/codecov-action@v4
with:
files: ./coverage/lcov.info
pipeline {
stages {
stage('Test') {
steps {
sh 'npm ci'
sh 'npm test'
publishHTML([
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
}
beforeEach(module('myApp'))beforeEach(inject(...))$rootScope.$apply() or $httpBackend.flush()done() callback: it('...', function(done) { ... done(); })async/await or return a promisepassThrough() for unmocked requestsAngularJS was built for an older Node.js and browser ecosystem, but it still runs on modern runtimes with the right configuration.
karma-chrome-launcher with headless ChrometestEnvironment: 'jsdom' handles the browser globals — no real browser needed# GitHub Actions — headless Chrome with Karma
- uses: actions/setup-chrome@v1
with:
chrome-version: stable
- run: npm test
// karma.conf.js — headless Chrome for CI
browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
}
arguments.callee will fail in strict mode. Use 'use strict' in test files to catch these early.npm audit --production to separate real risks from dev-only warnings, and consider overrides in package.json to pin patched transitive dependencies.When the time comes to move off AngularJS, here is the conceptual mapping:
| AngularJS | Angular 19+ |
|---|---|
| Modules / controllers | Standalone components or NgModules, injectable services |
$scope / $rootScope | Component state, @Input() / @Output(), signals |
$http / $resource | HttpClient |
| Directives | Components and directives with modern APIs |
$q / digest cycle | RxJS, promises/async-await, signals |
$routeProvider | Angular Router |
angular.module() DI | Tree-shakable providers, inject() |
| Globals and ad-hoc DOM | Dependency injection and testable abstractions |
Hybrid migration: Use @angular/upgrade to run AngularJS and Angular side by side. Migrate component-by-component rather than rewriting the whole app at once. The AngularJS test suite stays active throughout — Jest is the best runner for hybrid repos because it handles both AngularJS and Angular test files.
@angular/upgrade for incremental migration — your test suite migrates with youSpecialization: AngularJS Unit Testing with Jasmine and Jest
Version: 2.0
Last Updated: May 2026