Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Testing Infrastructure in Angular 22: Vitest, the unit-test Builder, jsdom and What to Test at Which Level
Angular 22's unit-test builder runs Vitest with isolation off, so state kept in a module can carry over between test files depending on the worker count, and a suite that is green locally turns red in CI. In this post we map the test levels for Bookstore's Angular client, set up the angular.json test target with setupFiles, providersFile and runnerConfig, measure jsdom against happy-dom, and run and debug single tests.
Testing Services, Pipes, Signals and Resources in Angular: TestBed.inject, HttpTestingController and Fake Timers
httpResource reports loading right away but sends the request inside an effect; a test needs TestBed.tick() to see the request and whenStable() to read the value after the response. Using Bookstore's CatalogService, PricePipe and RecentlyViewed, we show runInInjectionContext, effect tests, cancellation and the error path with HttpTestingController, fake timers for debounced(), and the resource timing change in Angular 22, all with real runs.
Angular Component Tests: setInput, outputs, whenStable in Zoneless Apps, @defer and Host Components
In Angular 22, old tests that assign through componentInstance and call detectChanges fail, because default OnPush and the zoneless fixture only process changes Angular is notified about; pass values with setInput and read the DOM after whenStable. With Bookstore's BookCard, QuantityInput, CartSummary and CatalogPage components we cover outputs, model(), content projection, @defer and getLastFixture, all with real runs.
Testing Like a User with Angular Testing Library: render, Role Queries and user-event
Testing like a user means finding elements by role and label and interacting in the order a user does: the test written with fireEvent.input failed because it skipped the blur that marks the field as touched, while the user-event version passed. On Bookstore's Signal Forms checkout form we cover render(), query priority, error messages tied with aria-describedby, findBy for async content, navigation with routes and a comparison with the same TestBed test, all with real runs.
Faking Dependencies in Angular Tests: Provider Overrides, vi.fn, ng-mocks, MSW and RouterTestingHarness
Fake what leaves the process, such as HTTP, time and browser APIs, and keep cheap dependencies like CartStore and the router real: a test that mocked everything missed a bug that emptied the cart before placing the order. On Bookstore's checkout and order detail pages we show provider overrides, vi.fn, vi.spyOn, hand-written fakes, child components with ng-mocks, network-level fakes with MSW 3 and RouterTestingHarness tests with the real routes, all with real runs.
Component Harnesses: Using CDK Harnesses, Writing Your Own and Decoupling Tests from Markup
A component harness puts an API between the test and the DOM: when the markup changes, only the harness changes, not the tests. On Bookstore we show Angular Material's select and dialog harnesses, documentRootLoader and the animation setting, our own harness with HarnessPredicate for RatingInput, and when to choose a harness or Testing Library, all with real runs.
Vitest Browser Mode: Running Angular Tests in Real Chromium, Firefox and WebKit
Test layout-dependent behavior (IntersectionObserver, @defer on viewport, sticky positioning, appearance) in a real browser with Vitest browser mode, not in jsdom. On Bookstore we show an infinite scroll bug that loaded only 24 of 30 books on a wide screen while the jsdom test passed, with a separate test target, the MSW worker, toMatchScreenshot and Chromium and WebKit runs.
Angular E2E with Playwright: Locators, Auto-Waiting, Network Mocking, storageState and the Trace Viewer
To E2E test an Angular UI without a backend, wire Playwright to ng e2e, fake the API with an automatic page.route fixture and treat every unanswered request as a failure; otherwise the development server returns index.html. On Bookstore's search, cart and checkout flow we show role-based locators, signing in once with storageState, traces and sources of flaky tests, all with real runs.
Migrating from Karma and Jasmine to Vitest and What Changed in Angular Testing from 12 to 22
Moving from Karma to Vitest takes two steps: migrate-karma-to-vitest converts the build settings and refactor-jasmine-vitest the test code, but a clean report does not mean the tests are right. On Bookstore's old client we show the check lost when the done callback was removed, mock types that did not compile, two ways to handle fakeAsync, a gradual move alongside Karma and what changed in Angular testing from 12 to 22, all with real runs.