From ng
Write Angular unit tests. Use automatically when creating .spec.ts files, when asked to test Angular components/services/pipes/directives/guards, or when reviewing test coverage. Supports Jest and Jasmine/Karma. Mirrors Angular testing documentation.
npx claudepluginhub mayeedwin/angular-plugin --plugin ngThis skill uses the workspace's default tool permissions.
**Primary reference**: https://angular.dev/guide/testing — always consult for current testing APIs.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Primary reference: https://angular.dev/guide/testing — always consult for current testing APIs.
package.json for jest (Jest) vs karma (Jasmine/Karma)jest.config.js or jest.config.ts (Jest)karma.conf.js (Karma/Jasmine)Use jest.fn() for Jest mocks, jasmine.createSpy() for Jasmine mocks.
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { {Name}Component } from './{name}.component';
describe('{Name}Component', () => {
let component: {Name}Component;
let fixture: ComponentFixture<{Name}Component>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [{Name}Component], // standalone: import directly, not declarations
}).compileComponents();
fixture = TestBed.createComponent({Name}Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { {Name}Component } from './{name}.component';
import { {Name}Service } from '../services/{name}.service';
// Jest
const mockService = {
getData: jest.fn().mockReturnValue(of([])),
};
// Jasmine
// const mockService = jasmine.createSpyObj('{Name}Service', ['getData']);
describe('{Name}Component', () => {
let component: {Name}Component;
let fixture: ComponentFixture<{Name}Component>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [{Name}Component],
providers: [
{ provide: {Name}Service, useValue: mockService },
],
}).compileComponents();
fixture = TestBed.createComponent({Name}Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should load data on init', () => {
expect(mockService.getData).toHaveBeenCalled();
});
});
it('should update count signal', () => {
component.increment();
fixture.detectChanges();
expect(component.count()).toBe(1);
});
import { TestBed } from '@angular/core/testing';
import { {Name}Service } from './{name}.service';
describe('{Name}Service', () => {
let service: {Name}Service;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject({Name}Service);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';
import { {Name}Service } from './{name}.service';
describe('{Name}Service', () => {
let service: {Name}Service;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting(),
],
});
service = TestBed.inject({Name}Service);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => httpMock.verify());
it('should fetch data', () => {
const mockData = [{ id: 1 }];
service.getAll().subscribe(data => {
expect(data).toEqual(mockData);
});
const req = httpMock.expectOne('/api/{name}');
expect(req.request.method).toBe('GET');
req.flush(mockData);
});
});
import { {Name}Pipe } from './{name}.pipe';
describe('{Name}Pipe', () => {
const pipe = new {Name}Pipe();
it('should transform value', () => {
expect(pipe.transform('input')).toBe('expected-output');
});
it('should handle null/undefined', () => {
expect(pipe.transform(null)).toBe('');
});
});
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Component } from '@angular/core';
import { {Name}Directive } from './{name}.directive';
@Component({
standalone: true,
imports: [{Name}Directive],
template: `<div app{Name}>test</div>`,
})
class TestHostComponent {}
describe('{Name}Directive', () => {
let fixture: ComponentFixture<TestHostComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TestHostComponent],
}).compileComponents();
fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
});
it('should apply directive', () => {
const el = fixture.nativeElement.querySelector('[app{Name}]');
expect(el).toBeTruthy();
});
});
import { {name}Reducer, initialState } from './reducer';
import * as {Name}Actions from './actions';
describe('{name}Reducer', () => {
it('should set loading true on load action', () => {
const state = {name}Reducer(initialState, {Name}Actions.load{Name}());
expect(state.loading).toBe(true);
});
it('should populate data on success', () => {
const data = [{ id: 1 }];
const state = {name}Reducer(initialState, {Name}Actions.load{Name}Success({ data }));
expect(state.data).toEqual(data);
expect(state.loading).toBe(false);
});
});
import { select{Name}Data } from './selectors';
describe('{name} selectors', () => {
const state = { data: [{ id: 1 }], loading: false, error: null };
it('should select data', () => {
expect(select{Name}Data.projector(state)).toEqual(state.data);
});
});
import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { Observable, of } from 'rxjs';
import { cold, hot } from 'jest-marbles'; // or 'jasmine-marbles'
import { load{Name}Effect } from './effects';
import { {Name}Service } from '../services/{name}.service';
import * as {Name}Actions from './actions';
describe('load{Name}Effect', () => {
let actions$: Observable<any>;
const mockService = { getAll: jest.fn() };
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideMockActions(() => actions$),
{ provide: {Name}Service, useValue: mockService },
],
});
});
it('should dispatch success on load', () => {
const data = [{ id: 1 }];
mockService.getAll.mockReturnValue(of(data));
actions$ = hot('-a', { a: {Name}Actions.load{Name}() });
const expected = cold('-b', { b: {Name}Actions.load{Name}Success({ data }) });
expect(TestBed.runInInjectionContext(() => load{Name}Effect())).toBeObservable(expected);
});
});
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { {name}Guard } from './{name}.guard';
import { AuthService } from '@core/services/auth.service';
describe('{name}Guard', () => {
let authService: jest.Mocked<AuthService>;
let router: jest.Mocked<Router>;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: AuthService, useValue: { isAuthenticated: jest.fn() } },
{ provide: Router, useValue: { navigate: jest.fn() } },
],
});
authService = TestBed.inject(AuthService) as jest.Mocked<AuthService>;
router = TestBed.inject(Router) as jest.Mocked<Router>;
});
it('should allow access when authenticated', () => {
authService.isAuthenticated.mockReturnValue(true);
const result = TestBed.runInInjectionContext(() =>
{name}Guard({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot)
);
expect(result).toBe(true);
});
});
afterEach(() => httpMock.verify()) when using HttpTestingControllerfixture.detectChanges() after state mutations in component tests.projector() — no store setup neededTestBed.runInInjectionContext() to test functional guards/effects