/
Angular Unit Testing Examples

Angular Unit Testing Examples

Purpose

This document provides sample unit tests for various Angular features, including forms (template-driven and reactive), pipes, directives, events, animations, services, asynchronous operations and more. These examples serve as a reference to ensure proper coverage and effective testing strategies.


1. Forms

Template-Driven Form

import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { TemplateFormComponent } from './template-form.component'; describe('TemplateFormComponent', () => { let component: TemplateFormComponent; let fixture: ComponentFixture<TemplateFormComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TemplateFormComponent], imports: [FormsModule], }).compileComponents(); fixture = TestBed.createComponent(TemplateFormComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should update form values correctly', () => { const formElement: HTMLInputElement = fixture.nativeElement.querySelector('input[name="username"]'); formElement.value = 'testuser'; formElement.dispatchEvent(new Event('input')); fixture.detectChanges(); expect(component.form.username).toBe('testuser'); }); });

Reactive Form

import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { ReactiveFormComponent } from './reactive-form.component'; describe('ReactiveFormComponent', () => { let component: ReactiveFormComponent; let fixture: ComponentFixture<ReactiveFormComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ReactiveFormComponent], imports: [ReactiveFormsModule], }).compileComponents(); fixture = TestBed.createComponent(ReactiveFormComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should mark the form as invalid if required field is empty', () => { component.formGroup.controls['username'].setValue(''); expect(component.formGroup.valid).toBeFalse(); }); it('should mark the form as valid with correct input', () => { component.formGroup.controls['username'].setValue('validuser'); expect(component.formGroup.valid).toBeTrue(); }); });

2. Pipes

import { UpperCasePipe } from './upper-case.pipe'; describe('UpperCasePipe', () => { const pipe = new UpperCasePipe(); it('should transform text to uppercase', () => { expect(pipe.transform('test')).toBe('TEST'); }); });

3. Directives

import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Component } from '@angular/core'; import { HighlightDirective } from './highlight.directive'; @Component({ template: `<p appHighlight>Test Text</p>` }) class TestHostComponent {} describe('HighlightDirective', () => { let fixture: ComponentFixture<TestHostComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [HighlightDirective, TestHostComponent], }); fixture = TestBed.createComponent(TestHostComponent); fixture.detectChanges(); }); it('should add highlight class on hover', () => { const paragraph = fixture.nativeElement.querySelector('p'); paragraph.dispatchEvent(new Event('mouseenter')); fixture.detectChanges(); expect(paragraph.classList).toContain('highlight'); }); });

4. Events

it('should emit an event on button click', () => { spyOn(component.buttonClicked, 'emit'); const button = fixture.nativeElement.querySelector('button'); button.click(); expect(component.buttonClicked.emit).toHaveBeenCalledWith('clicked'); });

5. Animations

import { trigger, state, style, transition, animate } from '@angular/animations'; describe('AnimationComponent', () => { it('should transition between states', () => { const animation = trigger('toggleState', [ state('off', style({ opacity: 0 })), state('on', style({ opacity: 1 })), transition('off => on', animate('1s')), transition('on => off', animate('1s')), ]); expect(animation.name).toBe('toggleState'); }); });

6. Services

import { TestBed } from '@angular/core/testing'; import { MyService } from './my-service.service'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; describe('MyService', () => { let service: MyService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [MyService], }); service = TestBed.inject(MyService); httpMock = TestBed.inject(HttpTestingController); }); it('should fetch data', () => { const mockData = [{ id: 1, name: 'Test' }]; service.getData().subscribe(data => { expect(data).toEqual(mockData); }); const req = httpMock.expectOne('api/data'); expect(req.request.method).toBe('GET'); req.flush(mockData); }); afterEach(() => { httpMock.verify(); }); });

7. Asynchronous Operations

it('should handle async operation', fakeAsync(() => { let data = ''; setTimeout(() => { data = 'Async Data'; }, 1000); tick(1000); expect(data).toBe('Async Data'); }));

8. Testing Guards

Example: CanActivate Guard

import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { AuthGuard } from './auth.guard'; import { AuthService } from './auth.service'; describe('AuthGuard', () => { let guard: AuthGuard; let authServiceMock: any; beforeEach(() => { authServiceMock = { isLoggedIn: jasmine.createSpy('isLoggedIn').and.returnValue(true), }; TestBed.configureTestingModule({ imports: [RouterTestingModule], providers: [ AuthGuard, { provide: AuthService, useValue: authServiceMock }, ], }); guard = TestBed.inject(AuthGuard); }); it('should allow navigation when logged in', () => { expect(guard.canActivate()).toBe(true); }); it('should prevent navigation when not logged in', () => { authServiceMock.isLoggedIn.and.returnValue(false); expect(guard.canActivate()).toBe(false); }); });

9. Testing Interceptors

Example: HTTP Interceptor

import { TestBed } from '@angular/core/testing'; import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http'; import { HttpTestingController, HttpClientTestingModule } from '@angular/common/http/testing'; import { AuthInterceptor } from './auth.interceptor'; describe('AuthInterceptor', () => { let httpMock: HttpTestingController; let httpClient: HttpClient; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, ], }); httpMock = TestBed.inject(HttpTestingController); httpClient = TestBed.inject(HttpClient); }); it('should add an Authorization header', () => { httpClient.get('/test').subscribe(); const httpRequest = httpMock.expectOne('/test'); expect(httpRequest.request.headers.has('Authorization')).toBe(true); httpMock.verify(); }); });

10. Testing Lifecycle Hooks

Example: Testing ngOnInit

import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my.component'; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [MyComponent], }); fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; }); it('should call ngOnInit', () => { spyOn(component, 'ngOnInit').and.callThrough(); fixture.detectChanges(); expect(component.ngOnInit).toHaveBeenCalled(); }); });

11. Mocking External Dependencies

Example: Mocking a Third-Party Library

import { TestBed } from '@angular/core/testing'; import { ExternalService } from 'external-library'; import { MyService } from './my.service'; describe('MyService', () => { let myService: MyService; let externalServiceMock: any; beforeEach(() => { externalServiceMock = { someMethod: jasmine.createSpy('someMethod').and.returnValue('mockValue'), }; TestBed.configureTestingModule({ providers: [ MyService, { provide: ExternalService, useValue: externalServiceMock }, ], }); myService = TestBed.inject(MyService); }); it('should use the mocked method', () => { expect(myService.useExternalService()).toBe('mockValue'); }); });

12. Integration Testing

Example: Multiple Component Interaction

import { TestBed, ComponentFixture } from '@angular/core/testing'; import { ParentComponent } from './parent.component'; import { ChildComponent } from './child.component'; describe('ParentComponent', () => { let fixture: ComponentFixture<ParentComponent>; let component: ParentComponent; beforeEach(() => { TestBed.configureTestingModule({ declarations: [ParentComponent, ChildComponent], }); fixture = TestBed.createComponent(ParentComponent); component = fixture.componentInstance; }); it('should interact with child component correctly', () => { fixture.detectChanges(); const childComponent = fixture.debugElement.query(By.directive(ChildComponent)).componentInstance; childComponent.someOutput.emit('test'); expect(component.handleChildOutput).toHaveBeenCalledWith('test'); }); });

13. Error Handling Tests

Example: Handling Service Errors

import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { MyService } from './my.service'; describe('MyService', () => { let service: MyService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [MyService], }); service = TestBed.inject(MyService); httpMock = TestBed.inject(HttpTestingController); }); it('should handle errors gracefully', () => { service.getData().subscribe( () => fail('Expected an error, not data'), (error) => { expect(error).toBeTruthy(); } ); const req = httpMock.expectOne('/data'); req.flush('Error', { status: 500, statusText: 'Server Error' }); }); });

14. Accessibility Testing

Example: Verifying ARIA Attributes

import { TestBed, ComponentFixture } from '@angular/core/testing'; import { MyComponent } from './my.component'; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [MyComponent], }); fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should have correct ARIA attributes', () => { const element = fixture.nativeElement.querySelector('.accessible-element'); expect(element.getAttribute('aria-label')).toBe('Expected Label'); }); });

15. Snapshot Testing

Example: Template Snapshot

import { TestBed } from '@angular/core/testing'; import { render } from '@testing-library/angular'; import { MyComponent } from './my.component'; describe('MyComponent Snapshot', () => { it('should match snapshot', async () => { const { container } = await render(MyComponent); expect(container).toMatchSnapshot(); }); });

15. Upload and Download Testing

Example: Template Snapshot

  • File Upload Test: Ensures that the uploadFile method sends a POST request with the correct file data and handles the expected response.

  • File Download Test: Ensures that the downloadFile method sends a GET request to the correct URL and returns the file content as a Blob.

import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { FileService } from './file.service'; describe('FileService', () => { let service: FileService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [FileService], }); service = TestBed.inject(FileService); httpMock = TestBed.inject(HttpTestingController); }); afterEach(() => { httpMock.verify(); }); /** * Unit Test for File Upload * This test ensures that the file upload function sends the correct request * and returns the expected response. */ it('should upload a file', () => { const dummyFile = new File(['test'], 'test-image.jpg', { type: 'image/jpeg' }); const uploadResponse = { success: true }; service.uploadFile(dummyFile).subscribe((response) => { expect(response.success).toBeTrue(); }); const req = httpMock.expectOne('/upload'); expect(req.request.method).toBe('POST'); expect(req.request.body.get('file')).toBe(dummyFile); req.flush(uploadResponse); }); /** * Unit Test for File Download * This test ensures that the file download function makes a correct HTTP GET request * and returns the expected file content (as a Blob). */ it('should download a file', () => { const dummyFileUrl = '/path/to/file'; const dummyBlob = new Blob(['dummy content'], { type: 'application/octet-stream' }); service.downloadFile(dummyFileUrl).subscribe((response) => { expect(response).toBeTruthy(); expect(response instanceof Blob).toBeTrue(); }); const req = httpMock.expectOne(dummyFileUrl); expect(req.request.method).toBe('GET'); req.flush(dummyBlob); }); });

Conclusion

These examples cover a wide range of Angular functionalities. Incorporating them into our testing process will ensure robust and reliable applications.

Related content