-
Notifications
You must be signed in to change notification settings - Fork 0
feat(docs): add the angular testing documentation #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a new Angular unit-testing example (app, tests, mocks, configs), a new Angular testing guide, and documentation navigation entries. Also updates several Angular example services and interceptors (mutation handlers, invalidateQueries returns, error signaling) and toggles a tsconfig flag for the devtools panel. Changes
Sequence Diagram(s)sequenceDiagram
participant C as UnitTestingComponent
participant S as TasksService
participant QC as QueryClient
participant HTTP as HttpClient
participant INT as MockInterceptor
C->>QC: injectQuery(allTasks)
QC->>S: call queryFn()
S->>HTTP: GET /api/tasks
HTTP->>INT: intercept GET
INT-->>HTTP: respond 200 [] (delayed)
HTTP-->>S: return []
S-->>QC: fulfill query
QC-->>C: data=[]
C->>QC: injectMutation(addTask).mutate({task, fail?})
QC->>S: call mutationFn()
S->>QC: onMutate (cancel + optimistic update)
S->>HTTP: POST /api/tasks or /api/tasks-wrong-url
HTTP->>INT: intercept POST
alt success
INT-->>HTTP: 201 success (delayed)
HTTP-->>S: success
S->>QC: onSuccess (no-op)
S->>QC: onSettled -> return invalidateQueries()
else error
INT-->>HTTP: throw Error (delayed)
HTTP-->>S: error
S->>QC: onError -> rollback using context
S->>QC: onSettled -> return invalidateQueries()
end
QC->>S: refetch allTasks
sequenceDiagram
participant TB as TestBed
participant RIC as runInInjectionContext
participant S as TasksService
participant QC as QueryClient
participant INT as MockInterceptor
TB->>RIC: provideHttpClient(withInterceptors([mockInterceptor]))
TB->>RIC: provideTanStackQuery(new QueryClient({ defaultOptions..., retries:0 }))
RIC->>S: instantiate TasksService
RIC->>QC: create query & mutation (allTasks, addTask)
QC->>INT: HTTP interactions intercepted & delayed
TB->>QC: poll isFetching / inspect getQueryData for optimistic updates and rollbacks
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @arvi18, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
I've focused on significantly improving the Angular documentation and examples related to testing with TanStack Query. This pull request introduces a dedicated guide for testing best practices and a fully functional unit testing example project. Additionally, I've made minor but important adjustments to existing examples to enhance error simulation and refine mutation lifecycle handling, ensuring a more robust and type-safe experience for developers.
Highlights
- New Angular Testing Documentation: I've added a brand new documentation guide at
docs/framework/angular/guides/testing.md
. This guide provides comprehensive information on how to effectively test Angular applications that utilize TanStack Query, including strategies for handling asynchronous operations like polling with@testing-library/angular
and managing query retries in tests. - New Angular Unit Testing Example Project: A complete new example project,
examples/angular/unit-testing/
, has been introduced. This project serves as a practical demonstration of setting up and performing unit tests for Angular applications with TanStack Query, featuring Jest and ESLint configurations, a sample service, a component, and a mock API interceptor for realistic testing scenarios. - Improved Error Simulation in Mock API Interceptors: The mock API interceptors in both the
optimistic-updates
example and the newunit-testing
example have been refined. They now usethrowError
from RxJS for simulating network errors, which provides a more accurate and robust way to test error handling compared to simply returning a 500 status response. - Enhanced Mutation and Query Lifecycle Handling: I've enhanced the mutation and query lifecycle handling in the
examples/angular/auto-refetching/src/app/services/tasks.service.ts
andexamples/angular/optimistic-updates/src/app/services/tasks.service.ts
files. This includes explicitly returninginvalidateQueries
calls inonSuccess
andonSettled
callbacks and improving type safety foronMutate
andonError
callback parameters, leading to more predictable and robust state management. - Documentation Navigation Updates: The
docs/config.json
file has been updated to seamlessly integrate the new content into the documentation navigation. This includes adding direct links to the new 'Testing' guide and the 'Unit Testing / Jest' example, making them easily discoverable for users.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
🤖 Refacto.AI: PR Summary & Reviewer Guide🎯 1. The Goal (Why was this PR raised?)This PR adds comprehensive documentation and examples for testing Angular applications that use TanStack Query. It introduces both testing guides and a complete working example demonstrating best practices for unit testing Angular services with TanStack Query. 🗺️ 2. The Changes (What was implemented?)
🤔 3. Key Areas for Human ReviewArea of Concern: Testing Documentation Completeness
Area of Concern: Test Example Implementation
Area of Concern: Mock API Interceptor
Area of Concern: Consistency with Other Frameworks
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces comprehensive documentation and a new example project for testing Angular applications with TanStack Query. The changes are extensive and well-structured. My review focuses on improving the new documentation and example code by enhancing type safety and addressing potential issues like stateful mocks that could lead to flaky tests. I've provided specific suggestions to use proper TypeScript types instead of any
, fix an error in a code example, and improve the robustness of the test setup.
} from '@angular/common/http' | ||
import type { Observable } from 'rxjs' | ||
|
||
let callNumber = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The callNumber
variable is declared at the module level, which makes it stateful across multiple tests if they run in the same process without module cache invalidation. This can lead to flaky and unpredictable test outcomes. It's crucial to reset this state before each test. Consider exporting a reset function from this module to be called in a beforeEach
block in your spec files.
Example:
// In mock-api.interceptor.ts
export function resetCallNumber() {
callNumber = 0;
}
// In your spec file
import { resetCallNumber } from '...';
describe('...', () => {
beforeEach(() => {
resetCallNumber();
// ... other setup
});
});
), | ||
mutationKey: ['tasks'], | ||
onSuccess: () => {}, | ||
onMutate: async ({ task }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
return previousTodos | ||
}, | ||
onError: (_err, _variables, context) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/refacto-test |
Refacto is reviewing this PR. Please wait for the review comments to be posted. |
Code Review: Angular Testing with TanStack Query👍 Well Done
📌 Files Processed
📝 Additional Comments
|
examples/angular/unit-testing/src/app/components/unit-testing.component.ts
Show resolved
Hide resolved
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (23)
examples/angular/unit-testing/jest.config.ts (1)
1-1
: Fix TypeScript import for better type safety.The ESLint error indicates that
import()
type annotations should be avoided in favor of explicit imports.Apply this diff to use a proper import:
+import type { Config } from 'jest'; + -const config: import('jest').Config = { +const config: Config = {examples/angular/unit-testing/tsconfig.spec.json (1)
3-7
: Consider adding Node type definitions if tests reference Node globalsIf your Jest setup or helpers reference Node globals (e.g., process, __dirname, setImmediate), add node to the types array. Otherwise, this is fine as-is.
Example:
- "types": ["jest"] + "types": ["jest", "node"]examples/angular/unit-testing/.eslintrc.cjs (1)
3-6
: Empty ESLint config — consider extending recommended presets for Angular, TypeScript, and JestIf this example is meant to be self-contained, extend standard presets. If you rely on a repo-level config, ignore this.
Proposed minimal config (requires corresponding deps installed):
-/** @type {import('eslint').Linter.Config} */ -const config = {} - -module.exports = config +/** @type {import('eslint').Linter.Config} */ +const config = { + root: true, + env: { es2021: true, browser: true, jest: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@angular-eslint/recommended', + 'plugin:jest/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.spec.json'], + tsconfigRootDir: __dirname, + }, + overrides: [ + { + files: ['**/*.spec.ts'], + env: { jest: true }, + }, + ], +} + +module.exports = configexamples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (2)
18-19
: Stateful callNumber may cause cross-test couplingcallNumber persists across GETs and tests. Ensure tests reset it (or sessionStorage) between runs to avoid order-dependent assertions.
Options:
- Reset between tests (e.g., in beforeEach): callNumber = 0; sessionStorage.removeItem('unit-testing-tasks')
- Or derive the suffix purely from storage length to keep it stateless.
28-43
: Minor readability: de-duplicate JSON.parse and simplify GET caseNot required, but factoring tasks into a local constant avoids repeating JSON.parse and clarifies the first vs subsequent call paths.
Example:
- case 'GET': - callNumber++; - if (callNumber === 1) { - return respondWith( - 200, - JSON.parse( - sessionStorage.getItem('unit-testing-tasks') || '[]', - ), - ) } else { - return respondWith( - 200, - JSON.parse( - sessionStorage.getItem('unit-testing-tasks') || '[]', - ).concat([`CallNumber ${callNumber}`]), - ) - } + case 'GET': { + callNumber++ + const tasks: string[] = JSON.parse( + sessionStorage.getItem('unit-testing-tasks') || '[]', + ) + return callNumber === 1 + ? respondWith(200, tasks) + : respondWith(200, tasks.concat([`CallNumber ${callNumber}`])) + }examples/angular/optimistic-updates/src/app/services/tasks.service.ts (2)
50-50
: Remove no-op onSuccess for claritySince onSettled handles invalidation, this empty handler adds noise.
- onSuccess: () => {},
51-75
: Align onMutate/variables typing to the mutation input for clarityonMutate narrows variables to { task: string } while mutationFn accepts { task: string; failMutation: boolean }. It works, but aligning types improves readability and future refactors.
Example:
- onMutate: async ({ task } : {task: string}) => { + onMutate: async ({ task }: { task: string; failMutation: boolean }) => { // Cancel any outgoing refetchesOptionally define a shared type:
type AddTaskVariables = { task: string; failMutation: boolean }…and use it in mutationFn, onMutate, and onError.
examples/angular/unit-testing/src/app/services/tasks.service.ts (3)
15-16
: Use readonly private fields for consistency and intentMatches other examples and prevents accidental reassignment.
- #queryClient = inject(QueryClient) // Manages query state and caching - #http = inject(HttpClient) // Handles HTTP requests + readonly #queryClient = inject(QueryClient) // Manages query state and caching + readonly #http = inject(HttpClient) // Handles HTTP requests
31-33
: Update the comment to reflect actual invalidation behaviorInvalidation happens in onSettled, while onSuccess is a no-op here.
- * On success, invalidates and refetch the "tasks" query cache to update the task list. + * Uses optimistic updates; always invalidates and refetches the "tasks" query in onSettled.
51-55
: Add an explicit type to onMutate parameter for clarityIt’s inferred, but explicit typing helps readability and prevents regressions.
- onMutate: async ({ task }) => { + onMutate: async ({ task }: { task: string; failMutation: boolean }) => {Optional: define a shared type and reuse across mutationFn, onMutate, and onError:
type AddTaskVariables = { task: string; failMutation: boolean }examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (6)
1-1
: Use single quotes for consistencyAngular style guide recommends single quotes for imports.
-import { TestBed } from "@angular/core/testing"; +import { TestBed } from '@angular/core/testing';
2-2
: Use single quotes for consistency-import { provideHttpClient, withFetch, withInterceptors } from "@angular/common/http"; +import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
3-3
: Use single quotes for consistency-import { QueryClient, injectMutation, injectQuery, provideTanStackQuery } from "@tanstack/angular-query-experimental"; +import { QueryClient, injectMutation, injectQuery, provideTanStackQuery } from '@tanstack/angular-query-experimental';
4-4
: Use single quotes for consistency-import { Injector, inject, runInInjectionContext } from "@angular/core"; +import { Injector, inject, runInInjectionContext } from '@angular/core';
6-8
: Use single quotes for consistency-import { mockInterceptor } from "../interceptor/mock-api.interceptor"; -import { TasksService } from "./tasks.service"; -import type { CreateQueryResult} from "@tanstack/angular-query-experimental"; +import { mockInterceptor } from '../interceptor/mock-api.interceptor'; +import { TasksService } from './tasks.service'; +import type { CreateQueryResult, CreateMutationResult } from '@tanstack/angular-query-experimental';
110-110
: Add missing semicolon- expect(allTasks.data()).toEqual([task, 'CallNumber 2']) + expect(allTasks.data()).toEqual([task, 'CallNumber 2']);examples/angular/unit-testing/angular.json (2)
81-81
: Default build to development for examples (faster DX)For a docs/example project, using development as the default build configuration improves iteration speed and keeps source maps on. Consider switching the default or aligning serve/build defaults.
- "defaultConfiguration": "production" + "defaultConfiguration": "development"
15-41
: Reconsider global skipTests in a testing-focused exampleGiven this project teaches testing, you might want the schematics to generate test files by default (at least for services/components) to reduce friction for learners.
- "@schematics/angular:component": { - "inlineTemplate": true, - "inlineStyle": true, - "skipTests": true - }, + "@schematics/angular:component": { + "inlineTemplate": true, + "inlineStyle": true, + "skipTests": false + }, - "@schematics/angular:service": { - "skipTests": true - } + "@schematics/angular:service": { + "skipTests": false + }docs/framework/angular/guides/testing.md (5)
6-15
: Clarify guidance, fix grammar, and reference toObservable correctlyTighten phrasing, correct grammar, and add the import location for toObservable.
-As there is currently no simple way to await a signal to reach a specific value we will use polling to wait in our test (instead of transforming our signals in observable and use RxJS features to filter the values). If you want to do like us for the polling you can use the angular testing library. +As there is currently no simple way to await a signal to reach a specific value, we’ll use polling in tests (instead of transforming signals into observables and filtering with RxJS). If you prefer polling, you can use the Angular Testing Library. @@ -Otherwise we recommend to use the toObservable feature from Angular. +Otherwise, we recommend using Angular’s toObservable utility: + +import { toObservable } from '@angular/core/rxjs-interop'
41-51
: Return type comment mismatch: this returns a Promise, not an ObservableThe code uses lastValueFrom and returns a Promise. Adjust the comment to avoid confusion.
- /** - * Fetches all tasks from the API. - * Returns an observable containing an array of task strings. - */ + /** + * Fetches all tasks from the API. + * Returns a Promise that resolves to an array of task strings. + */
56-65
: Optional: strengthen types for the query resultSince you already import CreateQueryResult, you can type the variable for better IntelliSense and safety.
-import type { CreateQueryResult} from "@tanstack/angular-query-experimental"; +import type { CreateQueryResult } from "@tanstack/angular-query-experimental"; @@ - let allTasks: any; + let allTasks: CreateQueryResult<Array<string>>;Also applies to: 91-95
126-133
: Speed up tests by reducing artificial delays or using fake timersThe interceptor adds 1000ms delays to every call, which slows the suite. Consider reducing to 50–100ms, or use Jest fake timers and advanceTimersByTime in tests.
- const respondWith = (status: number, body: any) => - of(new HttpResponse({ status, body })).pipe(delay(1000)) + const respondWith = (status: number, body: any) => + of(new HttpResponse({ status, body })).pipe(delay(100)) @@ - if (req.url === '/api/tasks-wrong-url') { - return throwError(() => new Error('error')).pipe(delay(1000)); + if (req.url === '/api/tasks-wrong-url') { + return throwError(() => new Error('error')).pipe(delay(100));Also applies to: 156-161
170-171
: Fix typos and pluralizationMinor editorial fixes for clarity.
-Instead of targetting a server for the data you should mock the requests. There are multiple way of handling the mocking, we recommend to use the Interceptor from Angular, see [here](https://angular.dev/guide/http/interceptors) for more details. -You can see the the Interceptor setup in the "Unit testing / Jest" examples. +Instead of targeting a server for data, you should mock requests. There are multiple ways to handle mocking; we recommend using an Angular HTTP interceptor. See [the docs](https://angular.dev/guide/http/interceptors) for details. +You can see the interceptor setup in the “Unit testing / Jest” examples.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
examples/angular/unit-testing/src/favicon.ico
is excluded by!**/*.ico
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (23)
docs/config.json
(2 hunks)docs/framework/angular/guides/testing.md
(1 hunks)examples/angular/auto-refetching/src/app/services/tasks.service.ts
(2 hunks)examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
(0 hunks)examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
(2 hunks)examples/angular/optimistic-updates/src/app/services/tasks.service.ts
(2 hunks)examples/angular/unit-testing/.devcontainer/devcontainer.json
(1 hunks)examples/angular/unit-testing/.eslintrc.cjs
(1 hunks)examples/angular/unit-testing/README.md
(1 hunks)examples/angular/unit-testing/angular.json
(1 hunks)examples/angular/unit-testing/jest.config.ts
(1 hunks)examples/angular/unit-testing/package.json
(1 hunks)examples/angular/unit-testing/src/app/app.component.ts
(1 hunks)examples/angular/unit-testing/src/app/app.config.ts
(1 hunks)examples/angular/unit-testing/src/app/components/unit-testing.component.ts
(1 hunks)examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
(1 hunks)examples/angular/unit-testing/src/app/services/tasks.service.spec.ts
(1 hunks)examples/angular/unit-testing/src/app/services/tasks.service.ts
(1 hunks)examples/angular/unit-testing/src/index.html
(1 hunks)examples/angular/unit-testing/src/main.ts
(1 hunks)examples/angular/unit-testing/tsconfig.app.json
(1 hunks)examples/angular/unit-testing/tsconfig.json
(1 hunks)examples/angular/unit-testing/tsconfig.spec.json
(1 hunks)
💤 Files with no reviewable changes (1)
- examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
🧰 Additional context used
🧬 Code Graph Analysis (7)
examples/angular/unit-testing/src/app/app.component.ts (2)
examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts (1)
Component
(10-72)examples/angular/unit-testing/src/app/components/unit-testing.component.ts (1)
Component
(10-67)
examples/angular/unit-testing/src/main.ts (1)
examples/angular/unit-testing/src/app/app.config.ts (1)
appConfig
(14-28)
examples/angular/unit-testing/src/app/app.config.ts (2)
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (1)
mockInterceptor
(20-64)packages/angular-query-experimental/src/providers.ts (2)
provideTanStackQuery
(93-111)withDevtools
(242-335)
examples/angular/unit-testing/src/app/components/unit-testing.component.ts (4)
examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts (1)
Component
(10-72)examples/angular/unit-testing/src/app/app.component.ts (1)
Component
(4-11)packages/angular-query-experimental/src/inject-query.ts (1)
injectQuery
(218-225)packages/angular-query-experimental/src/inject-mutation.ts (1)
injectMutation
(41-174)
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (1)
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts (1)
mockInterceptor
(18-53)
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (7)
examples/angular/optimistic-updates/src/app/services/tasks.service.ts (1)
addTask
(34-81)examples/angular/unit-testing/src/app/services/tasks.service.ts (1)
addTask
(34-82)examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts (1)
mockInterceptor
(18-53)examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (1)
mockInterceptor
(20-64)packages/angular-query-experimental/src/providers.ts (1)
provideTanStackQuery
(93-111)packages/angular-query-experimental/src/inject-query.ts (1)
injectQuery
(218-225)packages/angular-query-experimental/src/inject-mutation.ts (1)
injectMutation
(41-174)
examples/angular/unit-testing/src/app/services/tasks.service.ts (2)
examples/angular/auto-refetching/src/app/services/tasks.service.ts (1)
Injectable
(11-59)examples/angular/optimistic-updates/src/app/services/tasks.service.ts (1)
Injectable
(11-82)
🪛 ESLint
examples/angular/unit-testing/jest.config.ts
[error] 1-1: import()
type annotations are forbidden.
(@typescript-eslint/consistent-type-imports)
🪛 Biome (2.1.2)
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
[error] 45-47: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (19)
examples/angular/unit-testing/.devcontainer/devcontainer.json (1)
1-4
: LGTM!The devcontainer configuration is clean and appropriate for Node.js 22 development environment.
examples/angular/unit-testing/README.md (1)
1-7
: LGTM!The README provides clear and comprehensive instructions covering all major package managers and essential commands.
examples/angular/unit-testing/src/index.html (1)
1-13
: LGTM!Standard and well-structured HTML5 boilerplate for Angular application with appropriate meta tags and bootstrap element.
examples/angular/unit-testing/jest.config.ts (1)
1-5
: Jest configuration is functional and appropriate.The configuration correctly sets up Jest for the Angular project with proper source directory roots.
examples/angular/auto-refetching/src/app/services/tasks.service.ts (2)
40-42
: Improved async handling in mutation callback.Returning the promise from
invalidateQueries
provides better control flow and allows callers to wait for cache invalidation completion.
54-56
: Consistent async handling across mutations.Good consistency with the addTask mutation - both now return promises from their onSuccess callbacks.
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts (2)
9-9
: Good addition of throwError for improved error simulation.Adding throwError import enables more realistic error scenarios for testing.
49-49
: Enhanced error simulation for better testing.Using
throwError
instead of a 500 HttpResponse provides more realistic error scenarios that better simulate actual network failures.examples/angular/unit-testing/package.json (1)
1-37
: Comprehensive and well-structured package configuration.The dependencies are appropriate for Angular 19 with Jest testing setup. Good inclusion of Testing Library packages and consistent version pinning.
examples/angular/unit-testing/tsconfig.json (1)
1-32
: Excellent TypeScript configuration with comprehensive strict settings.The configuration enables all recommended strict type checking options and Angular compiler strictness settings, promoting type safety and best practices.
examples/angular/optimistic-updates/src/app/services/tasks.service.ts (1)
77-79
: LGTM: returning invalidateQueries from onSettledReturning the promise is useful for test determinism and consistent async handling.
examples/angular/unit-testing/src/app/services/tasks.service.ts (1)
77-79
: LGTM: returning invalidateQueries from onSettledGood for deterministic tests and consistent async flows.
examples/angular/unit-testing/tsconfig.app.json (1)
1-9
: LGTM!Standard Angular TypeScript configuration setup. The empty
types
array correctly excludes test types from the app build.examples/angular/unit-testing/src/main.ts (1)
1-5
: LGTM!Standard Angular standalone application bootstrap with proper error handling.
examples/angular/unit-testing/src/app/app.component.ts (1)
1-11
: LGTM!Clean root component setup with OnPush change detection strategy and proper standalone configuration.
examples/angular/unit-testing/src/app/app.config.ts (1)
1-28
: LGTM!Well-configured application setup with HTTP client, mock interceptor, and TanStack Query. The 24-hour gcTime is appropriate for the testing example.
docs/config.json (1)
710-713
: LGTM!Documentation navigation entries correctly added for Angular testing guide and unit testing example.
Also applies to: 1291-1294
examples/angular/unit-testing/src/app/components/unit-testing.component.ts (1)
1-67
: LGTM!Well-structured component demonstrating TanStack Query integration with Angular. Proper use of OnPush change detection, new control flow syntax, and reactive state management.
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (1)
46-111
: Well-structured and comprehensive test coverage!The test suite effectively covers:
- Initial query state validation
- Successful mutations with optimistic updates
- Error handling with rollback behavior
- Query cache inspection and validation
- Proper async testing patterns with
waitFor
Great job on providing thorough test examples for the Angular TanStack Query integration.
"test": { | ||
"builder": "@angular-builders/jest:run", | ||
"options": { | ||
"tsConfig": "tsconfig.spec.json", | ||
"configPath": "jest.config.ts", | ||
"rootDir": "." | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify Jest builder/config presence and dependencies
Ensure the referenced Jest setup exists and required packages are installed to avoid CI/runtime failures.
Run this script to validate presence and dependencies:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
BASE="examples/angular/unit-testing"
# Check files referenced by the 'test' target
for f in "$BASE/jest.config.ts" "$BASE/tsconfig.spec.json" "$BASE/angular.json"; do
if [[ ! -f "$f" ]]; then
echo "Missing file: $f" && exit 1
fi
done
# Check package.json for jest builder and preset
PKG="$BASE/package.json"
if [[ -f "$PKG" ]]; then
echo "Checking devDependencies in $PKG"
jq -e '.devDependencies["@angular-builders/jest"]' "$PKG" >/dev/null || { echo "Missing @angular-builders/jest"; exit 1; }
jq -e '.devDependencies["jest"]' "$PKG" >/dev/null || { echo "Missing jest"; exit 1; }
jq -e '.devDependencies["jest-preset-angular"]' "$PKG" >/dev/null || { echo "Missing jest-preset-angular"; exit 1; }
else
echo "Missing $PKG" && exit 1
fi
# Check zone.js is installed (polyfills includes it)
jq -e '.dependencies["zone.js"] // .devDependencies["zone.js"]' "$PKG" >/dev/null || { echo "Missing zone.js dependency"; exit 1; }
echo "Jest setup looks present."
Length of output: 1073
🏁 Script executed:
#!/bin/bash
set -euo pipefail
PKG="examples/angular/unit-testing/package.json"
echo "Zone.js in dependencies: $(jq -r '.dependencies["zone.js"] // "none"' $PKG)"
echo "Zone.js in devDependencies: $(jq -r '.devDependencies["zone.js"] // "none"' $PKG)"
Length of output: 399
Missing jest-preset-angular
in devDependencies
Our verification shows that while @angular-builders/jest
, jest
, and zone.js
are present, the jest-preset-angular
package is not listed under devDependencies in examples/angular/unit-testing/package.json
. Without it, the Jest setup will fail at runtime.
Please update your package.json:
• File: examples/angular/unit-testing/package.json
"devDependencies": {
"@angular-builders/jest": "<your-version>",
"jest": "<your-version>",
+ "jest-preset-angular": "<compatible-version>"
}
Once added, re-run npm install
(or yarn
) and verify the tests execute successfully.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
examples/angular/unit-testing/package.json: add the missing jest-preset-angular
entry to devDependencies so Jest can run with the Angular preset; update
package.json by adding a compatible "jest-preset-angular" version to
devDependencies (choose a version that matches your Angular/Jest setup), save
the file, then run npm install or yarn and verify tests run successfully.
case 'POST': | ||
const tasks = JSON.parse( | ||
sessionStorage.getItem('unit-testing-tasks') || '[]', | ||
) | ||
tasks.push(req.body) | ||
sessionStorage.setItem( | ||
'unit-testing-tasks', | ||
JSON.stringify(tasks), | ||
) | ||
return respondWith(201, { | ||
status: 'success', | ||
task: req.body, | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix switch-case declaration scoping (noSwitchDeclarations)
Declaring const tasks directly in a switch case can leak across cases. Wrap the case body in a block.
- case 'POST':
- const tasks = JSON.parse(
- sessionStorage.getItem('unit-testing-tasks') || '[]',
- )
- tasks.push(req.body)
- sessionStorage.setItem(
- 'unit-testing-tasks',
- JSON.stringify(tasks),
- )
- return respondWith(201, {
- status: 'success',
- task: req.body,
- })
+ case 'POST': {
+ const tasks = JSON.parse(
+ sessionStorage.getItem('unit-testing-tasks') || '[]',
+ )
+ tasks.push(req.body)
+ sessionStorage.setItem(
+ 'unit-testing-tasks',
+ JSON.stringify(tasks),
+ )
+ return respondWith(201, {
+ status: 'success',
+ task: req.body,
+ })
+ }
🧰 Tools
🪛 Biome (2.1.2)
[error] 45-47: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🤖 Prompt for AI Agents
In examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
around lines 44 to 57, the switch case for 'POST' declares const tasks directly
which can leak into other cases; wrap the entire case body in a block (add { ...
} after case 'POST':) and move the const/let declarations and sessionStorage
manipulations inside that block so the variables are scoped to the case.
if (req.url === '/api/tasks-wrong-url') { | ||
return throwError(() => new Error('error')).pipe(delay(1000)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Simulate HTTP errors with HttpErrorResponse for better realism
Returning a plain Error loses HTTP context (status, statusText, url). Prefer HttpErrorResponse so HttpClient error flows mirror real backend failures.
- if (req.url === '/api/tasks-wrong-url') {
- return throwError(() => new Error('error')).pipe(delay(1000));
- }
+ if (req.url === '/api/tasks-wrong-url') {
+ return throwError(
+ () =>
+ new HttpErrorResponse({
+ status: 500,
+ statusText: 'Internal Server Error',
+ url: req.url,
+ error: { message: 'error' },
+ }),
+ ).pipe(delay(1000))
+ }
Additionally add this import at the top:
-import { HttpResponse } from '@angular/common/http'
+import { HttpResponse, HttpErrorResponse } from '@angular/common/http'
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if (req.url === '/api/tasks-wrong-url') { | |
return throwError(() => new Error('error')).pipe(delay(1000)); | |
} | |
// At the top of mock-api.interceptor.ts | |
-import { HttpResponse } from '@angular/common/http'; | |
+import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; | |
// …later, around line 59… | |
if (req.url === '/api/tasks-wrong-url') { | |
- return throwError(() => new Error('error')).pipe(delay(1000)); | |
+ return throwError( | |
+ () => | |
+ new HttpErrorResponse({ | |
+ status: 500, | |
+ statusText: 'Internal Server Error', | |
+ url: req.url, | |
+ error: { message: 'error' }, | |
+ }), | |
+ ).pipe(delay(1000)); | |
} |
🤖 Prompt for AI Agents
In examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
around lines 59 to 61, the interceptor returns a plain Error for the simulated
HTTP failure which loses HTTP context; replace the throwError(() => new
Error('error')) with throwError(() => new HttpErrorResponse({ status: 500,
statusText: 'Server Error', url: req.url, error: 'error' })) and ensure you add
the import for HttpErrorResponse from '@angular/common/http' at the top of the
file so the simulated error includes status, statusText and url like a real
backend response.
/refacto-test |
Refacto is reviewing this PR. Please wait for the review comments to be posted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
examples/angular/devtools-panel/tsconfig.json (1)
2-2
: IscompileOnSave
necessary here? It’s editor-specific and often a no-op with modern Angular toolchains.This flag is primarily honored by certain editors (e.g., Visual Studio). VS Code and CLI/vite watchers typically ignore it, so it may add confusion without effect. If this is intentional for a specific workflow, consider documenting it in the devtools-panel README. Otherwise, consider removing for clarity.
Optional cleanup:
- "compileOnSave": true,
@coderabbitai full review |
✅ Actions performedFull review triggered. |
/refacto-test |
Refacto is reviewing this PR. Please wait for the review comments to be posted. |
Code Review: Angular Testing Implementation👍 Well Done
📌 Files Processed
📝 Additional Comments
|
this.#queryClient.invalidateQueries({ queryKey: ['tasks'] }) | ||
}, | ||
onMutate: async ({ task }) => { | ||
onSuccess: () => {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent Query Invalidation
The onSuccess handler no longer invalidates queries unlike other examples. This inconsistency could cause stale data to persist in the cache, affecting functional correctness.
Standards
- ISO-IEC-25010-Functional-Correctness-Appropriateness
- ISO-IEC-25010-Reliability-Maturity
onError: (data: any, _variables: any, _context: any) => { | ||
expect(data).toEqual(new Error('error')); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete Error Handling
Error callback doesn't verify that optimistic update was rolled back. Missing validation that queryClient state was properly restored after mutation error, which is a critical part of the optimistic update pattern.
Standards
- Logic-Verification-Completeness
- Business-Rule-Validation
- Algorithm-Correctness-Error-Handling
this.#queryClient.invalidateQueries({ queryKey: ['tasks'] }) | ||
}, | ||
onMutate: async ({ task }) => { | ||
onSuccess: () => {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent Return Pattern
Empty onSuccess callback differs from other services that return invalidateQueries. Inconsistent return patterns across similar methods create maintenance confusion when developers need to understand callback behavior.
Standards
- Clean-Code-Consistency
- Design-Pattern-Observer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (8)
examples/angular/unit-testing/src/app/services/tasks.service.ts (1)
35-35
: Type the callbacks and context; improve optimistic update when cache is empty
- Provide generics to mutationOptions to propagate types to onMutate/onError.
- Type onMutate/onError params explicitly.
- Rename previousTodos and optimistically set when cache is empty.
- return mutationOptions({ + return mutationOptions<string, Error, { task: string; failMutation?: boolean }, string[] | undefined>({ @@ - onSuccess: () => {}, - onMutate: async ({ task }) => { + onSuccess: () => {}, + onMutate: async ({ task }: { task: string }) => { @@ - const previousTodos = this.#queryClient.getQueryData<Array<string>>([ - 'tasks', - ]) + const previousTasks = this.#queryClient.getQueryData<string[]>(['tasks']) @@ - if (previousTodos) { - this.#queryClient.setQueryData<Array<string>>( - ['tasks'], - [...previousTodos, task], - ) - } + this.#queryClient.setQueryData<string[]>( + ['tasks'], + [...(previousTasks ?? []), task], + ) @@ - return previousTodos + return previousTasks }, - onError: (_err, _variables, context) => { + onError: (_err: Error, _variables: { task: string; failMutation?: boolean }, context?: string[]) => { if (context) { // Rollback the optimistic update - this.#queryClient.setQueryData<Array<string>>(['tasks'], context) + this.#queryClient.setQueryData<string[]>(['tasks'], context) } },Also applies to: 50-51, 57-67, 71-76
docs/framework/angular/guides/testing.md (1)
90-103
: Make test async; add strict typing; fix comment typoThe test uses await but isn’t async; also type allTasks and fix “interceptor” typo.
- it('should get all the Tasks', () => { - let allTasks: any; + it('should get all the Tasks', async () => { + let allTasks: CreateQueryResult<string[], Error>; runInInjectionContext(injector, () => { allTasks = injectQuery(() => service.allTasks()); }); expect(allTasks.status()).toEqual('pending'); expect(allTasks.isFetching()).toEqual(true); expect(allTasks.data()).toEqual(undefined); // We await the first result from the query - await waitFor(() => expect(allTasks.isFetching()).toBe(false), {timeout: 10000}); + await waitFor(() => expect(allTasks.isFetching()).toBe(false), { timeout: 10000 }); expect(allTasks.status()).toEqual('success'); - expect(allTasks.data()).toEqual([]); // Considering that the inteceptor is returning [] at the first query request. + expect(allTasks.data()).toEqual([]); // Considering that the interceptor returns [] on the first request. // To have a more complete example have a look at "unit testing / jest" });examples/angular/unit-testing/src/app/components/unit-testing.component.ts (1)
61-66
: Handle mutation errors and clear input only on successAdd onError handling (previously requested) and only clear input after a successful mutation.
- this.addMutation.mutate({ - task: this.newItem, - failMutation: this.failMutation, - }) - this.newItem = '' + this.addMutation.mutate( + { + task: this.newItem, + failMutation: this.failMutation, + }, + { + onSuccess: () => (this.newItem = ''), + onError: (err) => console.error('Failed to add task:', err), + }, + )examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (1)
14-14
: Type addTask instead of using anyThis improves IntelliSense and catches mistakes in callbacks/variables.
- let addTask: any; + let addTask: CreateMutationResult< + { status: string; task: string }, + Error, + { task: string; failMutation: boolean }, + unknown + >;examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (3)
18-18
: Reset module-scoped state to avoid test flakinessExpose a reset to clear
callNumber
(and optionally storage) between tests.let callNumber = 0; +// Useful for test isolation +export function resetMockApiState() { + callNumber = 0 + sessionStorage.removeItem('unit-testing-tasks') +}
44-57
: Wrap POST case body in a block (fix noSwitchDeclarations lint error)Prevents case-local declarations leaking across cases and satisfies Biome rule.
- case 'POST': - const tasks = JSON.parse( - sessionStorage.getItem('unit-testing-tasks') || '[]', - ) - tasks.push(req.body) - sessionStorage.setItem( - 'unit-testing-tasks', - JSON.stringify(tasks), - ) - return respondWith(201, { - status: 'success', - task: req.body, - }) + case 'POST': { + const tasks = JSON.parse( + sessionStorage.getItem('unit-testing-tasks') || '[]', + ) + tasks.push(req.body) + sessionStorage.setItem( + 'unit-testing-tasks', + JSON.stringify(tasks), + ) + return respondWith(201, { + status: 'success', + task: req.body, + }) + }
8-8
: Return HttpErrorResponse for realistic HTTP failures and generic messageImproves parity with real backend errors (status/url/statusText) and avoids leaking details.
-import { HttpResponse } from '@angular/common/http' +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'- if (req.url === '/api/tasks-wrong-url') { - return throwError(() => new Error('error')).pipe(delay(1000)); - } + if (req.url === '/api/tasks-wrong-url') { + return throwError( + () => + new HttpErrorResponse({ + status: 500, + statusText: 'Internal Server Error', + url: req.url, + error: { message: 'Invalid request' }, + }), + ).pipe(delay(1000)) + }Also applies to: 59-61
examples/angular/unit-testing/angular.json (1)
95-101
: Verify Jest preset and configs are present to avoid CI failuresEnsure
jest-preset-angular
is in devDependencies and referenced files exist.#!/bin/bash set -euo pipefail BASE="examples/angular/unit-testing" # Files referenced by the 'test' target for f in "$BASE/jest.config.ts" "$BASE/tsconfig.spec.json"; do [[ -f "$f" ]] || { echo "Missing file: $f"; exit 1; } done PKG="$BASE/package.json" [[ -f "$PKG" ]] || { echo "Missing $PKG"; exit 1; } echo "Checking devDependencies in $PKG" jq -e '.devDependencies["jest-preset-angular"]' "$PKG" >/dev/null || { echo "Missing jest-preset-angular"; exit 1; } jq -e '.devDependencies["jest"]' "$PKG" >/dev/null || { echo "Missing jest"; exit 1; } jq -e '.devDependencies["@angular-builders/jest"]' "$PKG" >/dev/null || { echo "Missing @angular-builders/jest"; exit 1; } echo "Jest setup looks present."
🧹 Nitpick comments (29)
examples/angular/unit-testing/.devcontainer/devcontainer.json (1)
1-4
: Align devcontainer tooling with README (pnpm/yarn/bun) or clarify npm-onlyThe image provides npm, but README suggests yarn/pnpm/bun. Either install them via Corepack or trim the README to npm-only to avoid confusion.
Apply this minimal addition to auto-enable Corepack-managed PMs:
{ "name": "Node.js", - "image": "mcr.microsoft.com/devcontainers/javascript-node:22" + "image": "mcr.microsoft.com/devcontainers/javascript-node:22", + "postCreateCommand": "corepack enable && corepack prepare pnpm@latest --activate && corepack prepare yarn@stable --activate" }examples/angular/devtools-panel/tsconfig.json (1)
2-2
: Question: Do we need compileOnSave here?Setting
"compileOnSave": true
is unusual for Angular CLI projects and diverges from the unit-testing example (false). Recommend removing for consistency unless there's a specific tooling need.- "compileOnSave": true,
If this was intentional, please note the rationale (e.g., editor plugin dependency).
examples/angular/unit-testing/README.md (1)
5-7
: Clarify commands per package manager and fix minor wordingExplicitly list the test command variants and keep punctuation consistent to reduce friction for new contributors.
-- `npm install` or `yarn` or `pnpm i` or `bun i` -- `npm run start` or `yarn start` or `pnpm start` or `bun start` -- `npm run test` to run the tests +- `npm install` or `yarn` or `pnpm i` or `bun i`. +- `npm run start` or `yarn start` or `pnpm start` or `bun start`. +- Run tests: `npm run test` (or `yarn test` / `pnpm test` / `bun test`).Given the devcontainer currently only guarantees npm, consider noting that yarn/pnpm/bun require local availability or enabling via Corepack.
examples/angular/auto-refetching/src/app/services/tasks.service.ts (1)
41-42
: LGTM; returning the invalidate promise is fine. Consider deduping the key and tightening typesChange looks good. To reduce duplication and strengthen typings:
- Extract a shared query key constant.
- Optionally annotate generics on mutationOptions for stricter types.
Example (outside the shown lines):
const TASKS_KEY = ['tasks'] as const; // ... onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: TASKS_KEY }),Confirm that returning the Promise from onSuccess aligns with your test expectations across all examples (consistent behavior in other services).
Also applies to: 55-56
examples/angular/unit-testing/.eslintrc.cjs (1)
3-6
: Empty ESLint config isn’t “ready-to-use”; add minimal env/ignores.This keeps Jest globals recognized and avoids linting build artifacts without introducing extra deps.
Apply:
/** @type {import('eslint').Linter.Config} */ -const config = {} +const config = { + root: true, + ignorePatterns: ['dist', 'coverage'], + env: { browser: true, es2022: true, jest: true }, +}examples/angular/optimistic-updates/src/app/services/tasks.service.ts (4)
30-34
: Docstring is stale; invalidation now happens in onSettled.Apply:
- /** - * Creates a mutation for adding a task. - * On success, invalidates and refetches the "tasks" query cache to update the task list. - */ + /** + * Creates a mutation for adding a task with an optimistic update. + * Always invalidates and refetches the "tasks" query cache in onSettled. + */
50-51
: Remove no-op onSuccess handler.It adds noise; onSettled already handles refetch.
Apply:
- onSuccess: () => {}, - onMutate: async ({ task } : {task: string}) => { + onMutate: async ({ task } : {task: string}) => {
57-69
: Rename previousTodos → previousTasks for consistency with domain naming.Pure readability.
Apply:
- const previousTodos = this.#queryClient.getQueryData<Array<string>>([ + const previousTasks = this.#queryClient.getQueryData<Array<string>>([ 'tasks', ]) @@ - if (previousTodos) { + if (previousTasks) { this.#queryClient.setQueryData<Array<string>>( ['tasks'], - [...previousTodos, task], + [...previousTasks, task], ) } - return previousTodos + return previousTasks
35-42
: Optional: Type mutation generics to get a typed context.This removes explicit any in onError and improves DX.
Apply:
- return mutationOptions({ + return mutationOptions<unknown, unknown, { task: string; failMutation: boolean }, Array<string> | undefined>({ mutationFn: ({ task, failMutation = false, }: { task: string failMutation: boolean }) =>- onError: (_err: any, _variables: any, context: any) => { + onError: (_err, _variables, context) => { if (context) { this.#queryClient.setQueryData<Array<string>>(['tasks'], context) } },Also applies to: 71-75
examples/angular/unit-testing/src/app/services/tasks.service.ts (5)
18-21
: JSDoc is misleading about return typeThis returns queryOptions (whose queryFn resolves a Promise), not an Observable.
Apply:
- * Returns an observable containing an array of task strings. + * Returns TanStack Query options; the queryFn resolves to a Promise<string[]>.
22-28
: Add explicit generics to queryOptions for stronger typesPrevents accidental any in consuming tests/docs.
- allTasks = () => - queryOptions({ + allTasks = () => + queryOptions<string[], Error>({ queryKey: ['tasks'], queryFn: () => { - return lastValueFrom(this.#http.get<Array<string>>('/api/tasks')); + return lastValueFrom(this.#http.get<string[]>('/api/tasks')); } })
36-42
: Make failMutation optional to match default valueType declares it required while a default is provided.
- }: { - task: string - failMutation: boolean - }) => + }: { + task: string + failMutation?: boolean + }) =>
77-81
: Invalidate on success only to avoid unnecessary refetch on errorsReduces wasted work when mutations fail. If you want “always refetch” for demo simplicity, ignore.
- // Always refetch after error or success: - onSettled: () => { - return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] }) - }, + // Refetch after success only: + onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['tasks'] }),Also applies to: 50-50
26-26
: Prefer firstValueFrom for single-emission HTTPSlightly clearer for HttpClient streams.
-import { lastValueFrom } from 'rxjs' +import { firstValueFrom } from 'rxjs' @@ - return lastValueFrom(this.#http.get<string[]>('/api/tasks')); + return firstValueFrom(this.#http.get<string[]>('/api/tasks'));docs/framework/angular/guides/testing.md (3)
6-14
: Tighten wording; proper casingMinor grammar/wording polish.
-As there is currently no simple way to await a signal to reach a specific value we will use polling to wait in our test (instead of transforming our signals in observable and use RxJS features to filter the values). If you want to do like us for the polling you can use the angular testing library. +Because there’s no simple way to await a signal reaching a specific value, we’ll poll in tests (instead of converting signals to Observables and filtering with RxJS). If you prefer polling, you can use the Angular Testing Library.
18-20
: Clarify sentence structure-Because the recommendation is to use services that provide the Query options through function this is what we are going to do. +We recommend exposing Query options via service functions, so the examples follow that pattern.
41-51
: Align types and description with the implementationUse string[] and correct return description.
- /** - * Fetches all tasks from the API. - * Returns an observable containing an array of task strings. - */ + /** + * Fetches all tasks from the API. + * Returns Query options whose queryFn resolves to string[]. + */ @@ - return lastValueFrom(this.#http.get<Array<string>>('/api/tasks')); + return lastValueFrom(this.#http.get<string[]>('/api/tasks'));examples/angular/unit-testing/tsconfig.spec.json (1)
1-8
: Broaden test type support and patterns (optional)Include Node types (often used in Jest configs) and recognize *.test.ts files.
{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", - "types": ["jest"] + "types": ["jest", "node"] }, - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] + "include": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.d.ts"] }examples/angular/unit-testing/src/app/app.component.ts (1)
4-10
: Prefer explicit closing tag for the child component (minor).Self-closing custom elements can confuse some tooling. Optional change for clarity:
- template: `<unit-testing />`, + template: `<unit-testing></unit-testing>`,examples/angular/unit-testing/src/app/app.config.ts (2)
25-26
: Gate devtools to non-production buildsAvoid bundling devtools in prod. Conditionally include it using isDevMode().
-import type { ApplicationConfig } from '@angular/core' +import type { ApplicationConfig } from '@angular/core' +import { isDevMode } from '@angular/core' @@ - withDevtools(), + ...(isDevMode() ? [withDevtools()] : []),
21-23
: Double-check long gcTime for example app24h cache GC is fine for demos, but can cause memory retention in bigger apps. Consider lowering or documenting why you want this.
examples/angular/unit-testing/src/app/components/unit-testing.component.ts (3)
31-33
: Prevent accidental double submitsDisable the Create button when input is empty or the mutation is pending.
- <button (click)="addItem()">Create</button> + <button (click)="addItem()" [disabled]="!newItem || addMutation.isPending()">Create</button>
34-37
: Guard against undefined data and avoid duplicate track keysCoalesce to an empty list and track by index to avoid runtime issues if data is undefined or contains duplicates.
- @for (task of tasks.data(); track task) { + @for (task of tasks.data() ?? []; track $index) { <li>{{ task }}</li> }
20-22
: Optional: add basic error state for the queryConsider showing an error when tasks query fails (e.g., network error) to aid testing and UX.
Also applies to: 43-46
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (4)
8-8
: Import CreateMutationResult for strong typingBring in CreateMutationResult to remove anys below.
-import type { CreateQueryResult} from "@tanstack/angular-query-experimental"; +import type { CreateQueryResult, CreateMutationResult } from "@tanstack/angular-query-experimental";
63-69
: Type onSuccess callback parametersAligns with the mutation’s data and variables shapes.
- onSuccess: (data: any, variables: any, _context: any) => { + onSuccess: ( + data: { status: string; task: string }, + _variables: { task: string; failMutation: boolean }, + _context: unknown + ) => {
97-100
: Type onError callback parametersUse Error and explicit variable/context types.
- onError: (data: any, _variables: any, _context: any) => { + onError: ( + data: Error, + _variables: { task: string; failMutation: boolean }, + _context: unknown + ) => {
24-31
: Optional: disable mutation retries explicitly in testsMutations default to no retry, but making it explicit prevents surprises if defaults change.
provideTanStackQuery(new QueryClient({ defaultOptions: { queries: { retry: false - } + }, + mutations: { + retry: false + } } }))examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (1)
24-26
: Add url/statusText in mocked responses for better fidelityMinor realism boost; harmless to existing tests.
- const respondWith = (status: number, body: any) => - of(new HttpResponse({ status, body })).pipe(delay(1000)) + const respondWith = (status: number, body: any) => + of( + new HttpResponse({ + status, + body, + url: req.url, + statusText: status === 201 ? 'Created' : 'OK', + }), + ).pipe(delay(1000))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
examples/angular/unit-testing/src/favicon.ico
is excluded by!**/*.ico
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
docs/config.json
(2 hunks)docs/framework/angular/guides/testing.md
(1 hunks)examples/angular/auto-refetching/src/app/services/tasks.service.ts
(2 hunks)examples/angular/devtools-panel/tsconfig.json
(1 hunks)examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
(0 hunks)examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
(2 hunks)examples/angular/optimistic-updates/src/app/services/tasks.service.ts
(2 hunks)examples/angular/unit-testing/.devcontainer/devcontainer.json
(1 hunks)examples/angular/unit-testing/.eslintrc.cjs
(1 hunks)examples/angular/unit-testing/README.md
(1 hunks)examples/angular/unit-testing/angular.json
(1 hunks)examples/angular/unit-testing/jest.config.ts
(1 hunks)examples/angular/unit-testing/package.json
(1 hunks)examples/angular/unit-testing/src/app/app.component.ts
(1 hunks)examples/angular/unit-testing/src/app/app.config.ts
(1 hunks)examples/angular/unit-testing/src/app/components/unit-testing.component.ts
(1 hunks)examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
(1 hunks)examples/angular/unit-testing/src/app/services/tasks.service.spec.ts
(1 hunks)examples/angular/unit-testing/src/app/services/tasks.service.ts
(1 hunks)examples/angular/unit-testing/src/index.html
(1 hunks)examples/angular/unit-testing/src/main.ts
(1 hunks)examples/angular/unit-testing/tsconfig.app.json
(1 hunks)examples/angular/unit-testing/tsconfig.json
(1 hunks)examples/angular/unit-testing/tsconfig.spec.json
(1 hunks)
💤 Files with no reviewable changes (1)
- examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
🧰 Additional context used
🪛 ESLint
examples/angular/unit-testing/jest.config.ts
[error] 1-1: import()
type annotations are forbidden.
(@typescript-eslint/consistent-type-imports)
🪛 LanguageTool
examples/angular/unit-testing/README.md
[grammar] ~7-~7: There might be a mistake here.
Context: ...start-
npm run test` to run the tests
(QB_NEW_EN)
docs/framework/angular/guides/testing.md
[grammar] ~170-~170: There might be a mistake here.
Context: ...ide/http/interceptors) for more details. You can see the the Interceptor setup in...
(QB_NEW_EN)
[grammar] ~171-~171: There might be a mistake here.
Context: ...tors) for more details. You can see the the Interceptor setup in the "Unit testing ...
(QB_NEW_EN)
[grammar] ~171-~171: There might be a mistake here.
Context: ...p in the "Unit testing / Jest" examples.
(QB_NEW_EN)
🪛 Biome (2.1.2)
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
[error] 45-47: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (10)
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts (1)
9-9
: Use HttpErrorResponse instead of Error in mock-api.interceptor.tsImport HttpErrorResponse and throw an HttpErrorResponse to preserve status, url, and error payload:
-import { HttpResponse } from '@angular/common/http' +import { HttpResponse, HttpErrorResponse } from '@angular/common/http' @@ - if (req.url === '/api/tasks-wrong-url') { - return throwError(() => new Error('error')).pipe(delay(1000)); - } + if (req.url === '/api/tasks-wrong-url') { + return throwError( + () => + new HttpErrorResponse({ + status: 500, + statusText: 'Internal Server Error', + url: req.url, + error: { message: 'error' }, + }), + ).pipe(delay(1000)) + }No existing spec tests assert on a generic Error in this example. Update any future tests to expect HttpErrorResponse instead.
examples/angular/unit-testing/tsconfig.json (1)
1-32
: Strict TS/Angular compiler settings LGTM.Good defaults for tests and example apps; no blocking issues spotted.
examples/angular/unit-testing/src/app/services/tasks.service.ts (2)
15-16
: Good use of Angular inject() with private fieldsClean DI with private fields for QueryClient and HttpClient.
15-16
: tsconfig target supports private fields Theexamples/angular/unit-testing/tsconfig.json
setstarget
toES2022
(≥ ES2021), so class private fields (#
) are supported.examples/angular/unit-testing/tsconfig.app.json (1)
1-9
: LGTM — standard Angular app tsconfig.This matches Angular’s default app config. Confirm that test-only types (e.g., jest, node) are declared in a separate tsconfig.spec.json so keeping
"types": []
here won’t break test typings.examples/angular/unit-testing/src/main.ts (1)
5-5
: Bootstrap flow looks good.Straightforward bootstrap with error logging. No changes needed.
examples/angular/unit-testing/src/index.html (1)
1-13
: LGTM.Minimal and correct Angular index.html. If you plan to host under a subpath (e.g., GitHub Pages), remember to adjust
<base href="/">
.examples/angular/unit-testing/src/app/app.component.ts (1)
5-9
: Good choice using OnPush and a standalone root.Solid defaults for perf and simplicity.
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (1)
51-86
: Nice work on realistic optimistic-update assertionsGood use of waitFor and cache inspection to verify optimistic updates and refetch behavior.
examples/angular/unit-testing/angular.json (1)
47-58
: Build target configuration looks solidPaths, polyfills, and tsconfig wiring are consistent for the sample app.
{ | ||
"label": "Testing", | ||
"to": "framework/angular/guides/testing" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Nav additions look correct; verify targets resolve at build time.
The new Angular “Testing” guide and “Unit Testing / Jest” example entries point to:
- framework/angular/guides/testing
- framework/angular/examples/unit-testing
Please confirm the corresponding pages exist and routes render in the docs site.
Run:
Also applies to: 1290-1294
🏁 Script executed:
#!/bin/bash
# Verify guide page exists
fd -t f -a 'testing.md' docs/framework/angular/guides -x echo FOUND {} || true
# Verify example route directory (index.mdx/md/tsx)
fd -t f -a 'index.*' docs/framework/angular/examples/unit-testing -x echo FOUND {} || true
Length of output: 364
Missing example route directory
The path docs/framework/angular/examples/unit-testing
does not exist, so its nav link in docs/config.json
(lines 710–713 and 1290–1294) will 404. Add that directory with an index.*
file or correct the config path.
🤖 Prompt for AI Agents
In docs/config.json around lines 710–713 (and also update the duplicate at
1290–1294), the nav entry points to docs/framework/angular/examples/unit-testing
which does not exist and will 404; either create the missing directory
docs/framework/angular/examples/unit-testing and add an index file (e.g.,
index.md or index.mdx) with the example content, or change both config.json
entries to point to the correct existing path for the Angular testing example so
the links resolve.
The library defaults to three retries with exponential backoff, which means that your tests are likely to timeout if you want to test an erroneous query. The easiest way to turn retries off is via the provideTanStackQuery during the TestBed setup as shown in the above example. | ||
|
||
## Testing Network Calls | ||
|
||
Instead of targetting a server for the data you should mock the requests. There are multiple way of handling the mocking, we recommend to use the Interceptor from Angular, see [here](https://angular.dev/guide/http/interceptors) for more details. | ||
You can see the the Interceptor setup in the "Unit testing / Jest" examples. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typos and grammar in user-facing docs
“These are visible to readers; let’s polish.”
-## Testing Network Calls
-
-Instead of targetting a server for the data you should mock the requests. There are multiple way of handling the mocking, we recommend to use the Interceptor from Angular, see [here](https://angular.dev/guide/http/interceptors) for more details.
-You can see the the Interceptor setup in the "Unit testing / Jest" examples.
+## Testing network calls
+
+Instead of targeting a server, mock the requests. There are multiple ways to do this; we recommend using an Angular HTTP interceptor (see the [docs](https://angular.dev/guide/http/interceptors) for details).
+You can see the interceptor setup in the “Unit testing / Jest” examples.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
The library defaults to three retries with exponential backoff, which means that your tests are likely to timeout if you want to test an erroneous query. The easiest way to turn retries off is via the provideTanStackQuery during the TestBed setup as shown in the above example. | |
## Testing Network Calls | |
Instead of targetting a server for the data you should mock the requests. There are multiple way of handling the mocking, we recommend to use the Interceptor from Angular, see [here](https://angular.dev/guide/http/interceptors) for more details. | |
You can see the the Interceptor setup in the "Unit testing / Jest" examples. | |
## Testing network calls | |
Instead of targeting a server, mock the requests. There are multiple ways to do this; we recommend using an Angular HTTP interceptor (see the [docs](https://angular.dev/guide/http/interceptors) for details). | |
You can see the interceptor setup in the “Unit testing / Jest” examples. |
🧰 Tools
🪛 LanguageTool
[grammar] ~170-~170: There might be a mistake here.
Context: ...ide/http/interceptors) for more details. You can see the the Interceptor setup in...
(QB_NEW_EN)
[grammar] ~171-~171: There might be a mistake here.
Context: ...tors) for more details. You can see the the Interceptor setup in the "Unit testing ...
(QB_NEW_EN)
[grammar] ~171-~171: There might be a mistake here.
Context: ...p in the "Unit testing / Jest" examples.
(QB_NEW_EN)
🤖 Prompt for AI Agents
In docs/framework/angular/guides/testing.md around lines 166 to 171, fix typos
and improve grammar: change "turn retries off" to "turn off retries" (or
"disable retries"), correct "targetting" to "targeting", change "multiple way"
to "multiple ways", remove the duplicated "the the" so it reads "You can see the
Interceptor setup...", and normalize capitalization/usage of "Interceptor" (use
lowercase "interceptor" unless it's a proper noun). Apply these edits inline to
the paragraph for a clearer, grammatical user-facing doc.
const config: import('jest').Config = { | ||
roots: ['<rootDir>/src/'], | ||
setupFilesAfterEnv: [] | ||
}; | ||
export default config; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix ESLint violation and provide a working Angular Jest preset.
Your config won’t run Angular tests as-is and fails the ESLint rule banning import()
type annotations. Replace the file with a preset-based config and proper typings.
-const config: import('jest').Config = {
- roots: ['<rootDir>/src/'],
- setupFilesAfterEnv: []
- };
- export default config;
+import type { Config } from 'jest'
+
+const config: Config = {
+ preset: 'jest-preset-angular',
+ testEnvironment: 'jsdom',
+ roots: ['<rootDir>/src/'],
+ testMatch: ['**/*.spec.ts'],
+ setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ { tsconfig: '<rootDir>/tsconfig.spec.json', stringifyContentPathRegex: '\\.html$' }
+ ]
+ },
+ moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'],
+}
+
+export default config
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const config: import('jest').Config = { | |
roots: ['<rootDir>/src/'], | |
setupFilesAfterEnv: [] | |
}; | |
export default config; | |
import type { Config } from 'jest' | |
const config: Config = { | |
preset: 'jest-preset-angular', | |
testEnvironment: 'jsdom', | |
roots: ['<rootDir>/src/'], | |
testMatch: ['**/*.spec.ts'], | |
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], | |
transform: { | |
'^.+\\.(ts|mjs|js|html)$': [ | |
'jest-preset-angular', | |
{ tsconfig: '<rootDir>/tsconfig.spec.json', stringifyContentPathRegex: '\\.html$' } | |
] | |
}, | |
moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'], | |
} | |
export default config |
🧰 Tools
🪛 ESLint
[error] 1-1: import()
type annotations are forbidden.
(@typescript-eslint/consistent-type-imports)
🤖 Prompt for AI Agents
In examples/angular/unit-testing/jest.config.ts lines 1-5, the file uses the
banned import() type annotation and lacks a working Angular preset; replace it
with a preset-based config that avoids import() types by importing the Jest type
(e.g. import type { Config } from 'jest') and declare const config: Config = {
preset: 'jest-preset-angular', roots: ['<rootDir>/src/'], setupFilesAfterEnv:
['<rootDir>/setup-jest.ts'], testEnvironment: 'jest-environment-jsdom' } and
export default config so ESLint is satisfied and Angular tests run with the
proper preset and typings.
💡 Verification agent
🧩 Analysis chain
Ensure Jest loads a TypeScript config file in your environment.
If you’re not using a builder that can load TS configs, either:
- keep this file as .ts and configure Jest to load it via ts-node, or
- rename to jest.config.cjs/.js.
Also verify that these files exist and are referenced correctly: setup-jest.ts and tsconfig.spec.json.
🏁 Script executed:
#!/bin/bash
# Verify supporting files and preset
fd -a 'setup-jest.ts' -x echo 'FOUND {}' || true
fd -a 'tsconfig.spec.json' -x echo 'FOUND {}' || true
rg -n --hidden -S "jest-preset-angular" -g '!**/node_modules/**'
Length of output: 2044
Ensure Jest can load your TS config
Jest won’t pick up jest.config.ts
out of the box—either rename it to jest.config.cjs
(with module.exports = config
) or invoke Jest with --require ts-node/register
(and install ts-node
) so it can process the .ts
file.
Fix missing setup file
There’s no setup-jest.ts
in the repo but setupFilesAfterEnv
is empty—you’ll need to either add your setup-jest.ts
under examples/angular/unit-testing/
or remove any docs/reference to it.
tsconfig.spec.json is present
The tsconfig.spec.json
at examples/angular/unit-testing/tsconfig.spec.json
exists and needs no changes.
🧰 Tools
🪛 ESLint
[error] 1-1: import()
type annotations are forbidden.
(@typescript-eslint/consistent-type-imports)
🤖 Prompt for AI Agents
In examples/angular/unit-testing/jest.config.ts lines 1-5 the TS Jest config
won't be loaded by Jest by default and setupFilesAfterEnv is empty while a setup
file is referenced elsewhere; fix by either renaming this file to
jest.config.cjs and export with module.exports = config, or keep the .ts file
and ensure test runs include --require ts-node/register and add ts-node as a dev
dependency so Jest can process TypeScript configs; then either add a
setup-jest.ts under examples/angular/unit-testing/ and reference it in
setupFilesAfterEnv, or remove any docs/references to a setup file to avoid a
missing-import error (tsconfig.spec.json at
examples/angular/unit-testing/tsconfig.spec.json is fine and needs no changes).
"devDependencies": { | ||
"@angular/build": "^19.2.5", | ||
"@angular-builders/jest": "^19.0.0", | ||
"@angular/cli": "^19.2.5", | ||
"@angular/compiler-cli": "^19.2.4", | ||
"@testing-library/angular": "17.3.7", | ||
"@testing-library/dom": "^10.0.0", | ||
"@testing-library/jest-dom": "^6.4.8", | ||
"@types/jest": "^29.5.12", | ||
"@types/node": "^12.11.1", | ||
"jest": "^29.7.0", | ||
"ts-node": "~10.8.1", | ||
"typescript": "5.8.2" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Update Node types and declare engines to match Angular 19.
@types/node 12 is outdated for modern Angular/Jest stacks and can cause ambient type conflicts. Declare a Node engine and bump types.
Apply:
"devDependencies": {
@@
- "@types/node": "^12.11.1",
+ "@types/node": "^20",
@@
- "typescript": "5.8.2"
+ "typescript": "5.8.2"
}
+ ,
+ "engines": {
+ "node": ">=20"
+ }
If tests use ESM, ensure Jest transform is configured accordingly (ts-jest or swc). Verify:
🏁 Script executed:
#!/bin/bash
rg -n 'transform|preset|ts-jest|@swc' examples/angular/unit-testing/jest.config.ts -C2 || true
Length of output: 95
🏁 Script executed:
#!/bin/bash
# List any Jest config files in the example directory
find examples/angular/unit-testing -maxdepth 1 -type f -iname 'jest.config*'
# If jest.config.ts exists, print its contents for inspection
if [[ -f examples/angular/unit-testing/jest.config.ts ]]; then
sed -n '1,200p' examples/angular/unit-testing/jest.config.ts
fi
Length of output: 368
Update Node types & engines; configure Jest for TypeScript
- In examples/angular/unit-testing/package.json, bump
@types/node
and declare a minimum Node version:
"devDependencies": {
@@
- "@types/node": "^12.11.1",
+ "@types/node": "^20",
@@
- "typescript": "5.8.2"
+ "typescript": "5.8.2"
},
+ "engines": {
+ "node": ">=20"
+ }
- In examples/angular/unit-testing/jest.config.ts, there is no
preset
ortransform
configured. Add a TypeScript transformer or preset (for example,) so Jest can compile and runpreset: 'jest-preset-angular', transform: { '^.+\\.(ts|html)$': 'ts-jest' }
.ts
tests.
🤖 Prompt for AI Agents
In examples/angular/unit-testing/package.json around lines 23 to 36, bump the
@types/node dependency to a modern compatible version (e.g. ^18.x or ^20.x as
project requires) and add an "engines" field at the package root declaring the
minimum Node version (e.g. "engines": { "node": ">=18.0.0" }) to enforce runtime
compatibility; then in examples/angular/unit-testing/jest.config.ts (the
referenced config), add a preset and transform to compile TypeScript tests by
setting preset to "jest-preset-angular" and adding a transform mapping such as
'^.+\\.(ts|html)$' to 'ts-jest' (or use an equivalent ts transformer) so Jest
can process .ts/.html files, and ensure ts-jest and jest-preset-angular are
installed in devDependencies.
New Features
Introduced a comprehensive guide on testing Angular applications with TanStack Query, including examples and best practices.
Added a new Angular unit testing example project with full configuration, sample service, component, and mock API interceptor.
Provided ready-to-use Jest and ESLint configurations for Angular unit testing.
Included detailed documentation and setup instructions for the new unit testing example.
Bug Fixes
Improved error simulation in mock API interceptors for more accurate testing scenarios.
Refactor
Enhanced mutation and query lifecycle handling in Angular service examples for better type safety and control flow.
Documentation
Updated Angular documentation to include new testing guides and unit testing examples.
Summary by CodeRabbit
New Features
Tests
Documentation
Refactor
Chores