Testing
Test Runner and Framework
All unit tests are executed with Karma as the test runner, using Jasmine as the testing framework. Karma provides a fast, real‑browser environment suitable for Angular libraries and integrates seamlessly with the Angular CLI workspace.
Configuration is shared through a root karma.conf.js, extended by each library as needed. The minimum setup includes:
Browser: ChromeHeadless for CI, locally configurable.
Reporters:
progressandjunit(for CI reporting).Frameworks:
jasmine.Files: compiled TypeScript spec files colocated with sources (see 5.5).
The Angular CLI’s ng test command is the primary way to invoke tests locally. Customization (e.g., adding polyfills or adjusting timeouts) is allowed at the library level only when strictly necessary and must be documented.
Test Data Generation with @artstesh/forger
To ensure deterministic, maintainable, and realistic test data, all mocks and stubs must be created using the * @artstesh/forger* library. It provides a declarative API for fabricating objects, arrays, and primitive values with controllable variation, making tests more robust and less dependent on fragile hand‑written fixtures.
Usage rules:
Every test that requires data structures (models, DTOs, configuration objects) must use
forgerto generate them.Avoid hard‑coded test data that inadvertently reflects real production values or breaks when models change.
Example:
import { Forger } from '@artstesh/forger'; import { UserModel } from './user.model'; export const user = Forger.create<UserModel>();
The library’s public API must be fully typed; using Forger guarantees that generated objects satisfy those types at the type level.
Event‑Driven Testing with @artstesh/postboy-testing
All libraries and applications rely on an Event‑Driven Architecture powered by @artstesh/postboy. Consequently, any unit test that involves event dispatching, subscription, or handling must use the companion testing library * * @artstesh/postboy-testing**.
This library provides:
A controlled
PostboyServiceMock(a mock of the event bus) that captures all published events and allows spying on subscriptions.Utilities to simulate event sequences and verify that services react correctly.
Requirements:
Services or facades that depend on
postboymust be tested withPostboyServiceMockinjected.Every event‑producing method should have a test that verifies the event type, payload, and publication under various conditions.
Event handlers must be tested by publishing events on the test bus and asserting side effects (state changes, further dispatches, external calls).
Do not instantiate the real
PostboyServiceclass in unit tests; always usePostboyServiceMockfrom@artstesh/postboy-testing.
Example:
Unit Test Requirements and Coverage
Definition of Done for Non‑Visual Classes
Full unit test coverage is mandatory for all services, mappers, utilities, pipes, guards, interceptors, and any other classes that do not directly render HTML. This includes:
All public methods, including overloads.
All logical branches (if/else, switch cases, early returns).
Error handling paths (exceptions thrown, fallbacks).
Event‑driven interactions (publishing and reacting to events).
Proper test isolation: each test must set up its own context using mocks (from
Forger) and the test event bus.
Coverage metrics for these classes are enforced in CI. The target is:
Line coverage: ≥ 90%
Function coverage: 100% for public API
These thresholds apply to each non‑visual file individually and are checked at the library level.
Component Testing (Recommended)
Unit tests for Angular components (.component.ts files) are recommended but not required for DoD. When written, they should follow the same conventions:
Use
ng-mocksand mock all dependencies (services, postboy, forger for data).Focus on component logic (input/output interaction, event handling, lifecycle effects), not on the rendered DOM.
DOM‑focused tests and visual snapshots are outside the scope of unit testing; they are handled by Storybook and dedicated visual regression tools if needed.
While component tests are not part of the merge gate, teams are encouraged to add them for complex behavioural components (e.g., state machines, dynamic form generators). A low‑effort approach is to test only the component class instance (isolated unit tests without TestBed), which is fully acceptable.
Test Colocation and Naming
Unit test files are colocated with the source file they test. Naming convention:
my-service.service.spec.tsfor a service namedMyService.filter.component.spec.tsfor a component class.status.pipe.spec.tsfor a pipe.
CI Integration and Coverage Reporting
The CI pipeline executes unit tests for all libraries. The job:
After the run, coverage reports are generated in coverage/ and analysed:
Thresholds are enforced via
karma-coverage-istanbul-reporteror similar plugin.If any non‑visual source file fails to meet the threshold, the pipeline fails, blocking the merge.
The coverage report is published as an artifact, allowing developers to inspect uncovered branches.
Additionally, test results in JUnit format are collected for trend visualisation in CI dashboards. All tests must pass, with zero failures and zero skipped tests, for the pipeline to succeed.