How tests are wired, what helpers exist, and what the CI gate enforces.
- Test framework: Jasmine
- Runner: Karma (
karma.conf.js) - Browser: headless Chromium driven by Puppeteer. The custom launcher
ChromiumNoSandbox(base: 'ChromeHeadless'plus--no-sandbox,--disable-gpu, etc.) is whatnpm testand CI use. - Builder:
@angular/build:karmaconfigured inangular.jsonunder theinterviewer.architect.testtarget.tsConfig: tsconfig.spec.json.
karma.conf.js sets process.env.CHROME_BIN = require('puppeteer').executablePath() so a Puppeteer-bundled Chromium is always used — no system Chrome required.
npm test # ng test --browsers ChromiumNoSandbox (watch mode)
npm run test-headless-ci-only # ng test --no-watch --browsers ChromiumNoSandbox (CI gate)You can scope a run to a single spec the usual Angular CLI way:
ng test --browsers ChromiumNoSandbox --include='**/auth-interceptor.spec.ts'- Specs are colocated with their subject as
<file>.spec.ts. - Shared utilities live in
src/app/shared/test-utils/andsrc/app/shared/tests/. - Value-object tests live alongside their value object in
src/app/shared/value-objects/.
Three reusable bundles exported from index.ts:
testUtilStubs— DI stubs forHttpClient,Router,ActivatedRoute,Location. Use these instead of letting the real services run during unit tests.mostUsedServices— pre-wired session storage,AuthSessionService,MockAuthService,AlertService,CheckDeviceService,ApiService,TitleService,CookieService, and aMockGoogleAnalyticsService. Drop intoprovidersfor components that depend on the common infrastructure.mostUsedImports—BrowserModule,BrowserAnimationsModule,RouterTestingModule, the form modules,CommonModule,SharedModule,NgSelectModule. Drop intoimportsfor component tests.
Two helpers for "given a logged-in user" setup:
spyOnCurrentUserServiceWithUser(user, spyOnFn)— overridesAuthService.getCurrentUserto return a specificApplicationUserExtended.spyOnCurrentUserServiceWithUserId(spyOnFn, userId?, role?)— convenience wrapper that builds aTestApplicationUserand forwards.
MockAuthService (src/app/shared/test-utils/mock-auth.service.ts) is the default substitute for AuthService; TestApplicationUser (src/app/shared/test-utils/models/) is a builder for fixture users.
Provide HttpClient real (or stubbed via testUtilStubs) and TestBed.inject(MyService). Example: src/app/services/api.service.spec.ts uses provideHttpClient(withInterceptorsFromDi()) so the service can be exercised against an interceptor stack if needed.
Use HttpClientTestingModule-style fixtures (Angular's standard pattern). Examples: src/app/shared/interceptors/auth-interceptor.spec.ts, date-parser-interceptor.spec.ts. When changing the auth interceptor, the refresh-deduplication invariant (see authentication.md) must remain covered.
Examples: src/app/shared/guards/auth.guard.spec.ts, active-user.guard.spec.ts, is-desktop.guard.spec.ts. They typically inject MockAuthService and assert routing side-effects via RouterStub.
Pure-function style, no TestBed. Examples: src/app/shared/value-objects/date-extended.spec.ts, enum-helper.spec.ts, convert-object-to-http.spec.ts.
The Express sitemap redirect is unit-tested in src/server/sitemap-redirect.util.spec.ts. There is no end-to-end SSR rendering test in the suite; verify SSR behaviour manually with npm run serve:ssr:interviewer plus curl.
Triggered on pull requests targeting main:
- Cache
~/.npm. actions/setup-node@v2withnode-version: 23.npm install --include=optional(theoptionalDependenciesblock inpackage.jsonincludes Nx prebuilt binaries used elsewhere).npm run build-prod— must succeed (catches budget violations and SSR build failures).npm run test-headless-ci-only— must succeed.
npm run lint is currently commented out in CI; locally you can still run it. Lint locally before pushing if you've edited templates or selectors — the rules in .eslintrc.js are enforced strictly for @angular-eslint/component-selector and @angular-eslint/directive-selector.
Karma runs in a real headless browser, so window, document, and localStorage exist. SSR safety is not verified by the unit-test suite. To check that a change is SSR-safe, run:
npm run build
npm run serve:ssr:interviewer
curl -s http://localhost:4000/ | headA crash in the server bundle usually surfaces as a 500 from the SSR engine and a stack trace on stderr.
The project rule (CLAUDE.md):
After modifying any code that has existing tests, always run the full test suite before reporting completion.
That means npm run test-headless-ci-only, not a single spec.