--- paths: - "**/*.spec.ts" - "**/*.test.ts" --- # Angular Testing > This file extends [common/testing.md](../common/testing.md) with Angular specific content. ## Test Runner Use the test runner configured by the project. Check `angular.json` and `package.json`; Angular projects commonly use Vitest, Jest, or Jasmine + Karma. ```bash ng test # watch mode ng test --no-watch # CI mode ``` ## TestBed Setup For standalone components, import the component directly. Call `compileComponents()` for components with external templates. ```typescript describe('UserCardComponent', () => { let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [UserCardComponent], }).compileComponents(); fixture = TestBed.createComponent(UserCardComponent); }); }); ``` ## Signal Inputs Set signal-based inputs via `fixture.componentRef.setInput()`: ```typescript fixture.componentRef.setInput('user', mockUser); fixture.detectChanges(); ``` ## Component Harnesses Prefer Angular CDK component harnesses over direct DOM queries for UI interaction. Harnesses are more resilient to markup changes. ```typescript import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatButtonHarness } from '@angular/material/button/testing'; let loader: HarnessLoader; beforeEach(() => { loader = TestbedHarnessEnvironment.loader(fixture); }); it('triggers save on button click', async () => { const button = await loader.getHarness(MatButtonHarness.with({ text: 'Save' })); await button.click(); expect(saveSpy).toHaveBeenCalled(); }); ``` ## Router Testing Use `RouterTestingHarness` for components that depend on the router: ```typescript import { RouterTestingHarness } from '@angular/router/testing'; it('renders user on navigation', async () => { const harness = await RouterTestingHarness.create(); const component = await harness.navigateByUrl('/users/1', UserDetailComponent); expect(component.userId()).toBe('1'); }); ``` ## Async Testing Use `fakeAsync` + `tick` for controlled async. Use `waitForAsync` for real async with `fixture.whenStable()`. ```typescript it('loads user after delay', fakeAsync(() => { const service = TestBed.inject(UserService); vi.spyOn(service, 'getUser').mockReturnValue(of(mockUser)); fixture.detectChanges(); tick(); fixture.detectChanges(); expect(fixture.nativeElement.querySelector('.name').textContent).toBe(mockUser.name); })); ``` ## HTTP Testing ```typescript import { provideHttpClientTesting } from '@angular/common/http/testing'; import { HttpTestingController } from '@angular/common/http/testing'; beforeEach(() => { TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()], }); httpMock = TestBed.inject(HttpTestingController); }); afterEach(() => httpMock.verify()); ``` ## Service Testing Inject services directly without a component fixture: ```typescript describe('UserService', () => { let service: UserService; beforeEach(() => { TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()], }); service = TestBed.inject(UserService); }); }); ``` ## What to Test - **Services**: All public methods, error paths, HTTP interactions - **Components**: Input/output bindings, rendered output for key states, user interactions via harnesses - **Pipes**: Pure transformation — plain unit tests, no TestBed needed - **Guards/Resolvers**: Return values for allowed and denied states using `RouterTestingHarness` ## E2E Testing Use the project's configured E2E framework, such as Cypress or Playwright, for critical user flows. ```typescript describe('Login flow', () => { it('redirects to dashboard on valid credentials', () => { cy.visit('/login'); cy.get('[data-cy=email]').type('user@example.com'); cy.get('[data-cy=password]').type('password123'); cy.get('[data-cy=submit]').click(); cy.url().should('include', '/dashboard'); }); }); ``` - Add `data-cy` attributes to interactive elements for stable selectors - Do not rely on CSS classes or text content for selectors in E2E tests ## Coverage Target ≥80% for services and pipes. Components: test behaviour, not implementation details. ## Skill Reference See skill: `angular-developer` for comprehensive testing patterns, harness usage, and async best practices.