Skip to content

Conversation

gandalf-repo
Copy link

@gandalf-repo gandalf-repo commented Aug 10, 2025

This PR is to improve the testing doc of Angular package.
Let's discuss what is missing and you would like to be added.
BR

Summary by CodeRabbit
New Features

Added a comprehensive guide and examples for testing Angular applications, including a dedicated "Testing" section in the documentation.
Introduced a complete Angular unit testing example project with setup for Jest and Testing Library, including configuration files, mock API interceptor, and sample service with optimistic updates.
Provided a standalone Angular component and service demonstrating integration with TanStack Query and unit testing practices.
Documentation

Expanded Angular documentation with new guides and example links focused on testing and unit testing with Jest.
Tests

Added a detailed test suite for the Angular tasks service, covering optimistic updates, error handling, and cache management.

Summary by CodeRabbit

  • 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.

@coderabbitai
Copy link

coderabbitai bot commented Aug 10, 2025

Walkthrough

This update introduces a comprehensive Angular unit testing example using TanStack Query, Jest, and Angular Testing Library. It adds new documentation guides, configuration files, a full-featured Angular example with mocked API, and corresponding tests. Several service and interceptor implementations are provided, and existing Angular example services and interceptors are refined for better type safety and control flow.

Changes

Cohort / File(s) Change Summary
Documentation & Config Updates
docs/config.json, docs/framework/angular/guides/testing.md
Added a "Testing" guide and a "Unit Testing / Jest" example to Angular documentation. Introduced a detailed guide on Angular testing with TanStack Query, including sample services, interceptors, and tests.
New Angular Unit Testing Example: Configuration & Setup
examples/angular/unit-testing/README.md, examples/angular/unit-testing/package.json, examples/angular/unit-testing/angular.json, examples/angular/unit-testing/jest.config.ts, examples/angular/unit-testing/.eslintrc.cjs, examples/angular/unit-testing/.devcontainer/devcontainer.json, examples/angular/unit-testing/tsconfig.json, examples/angular/unit-testing/tsconfig.app.json, examples/angular/unit-testing/tsconfig.spec.json, examples/angular/unit-testing/src/index.html, examples/angular/unit-testing/src/main.ts
Introduced a new Angular unit testing example project with all supporting configuration: package, Angular workspace, Jest, ESLint, devcontainer, TypeScript, and HTML entry point.
Unit Testing Example: App, Services, Components, Interceptor, and Tests
examples/angular/unit-testing/src/app/app.component.ts, examples/angular/unit-testing/src/app/app.config.ts, examples/angular/unit-testing/src/app/components/unit-testing.component.ts, examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts, examples/angular/unit-testing/src/app/services/tasks.service.ts, examples/angular/unit-testing/src/app/services/tasks.service.spec.ts
Implemented the main Angular unit testing example: root component, app config, a unit testing component, mock API interceptor, a tasks service with TanStack Query, and a comprehensive test suite for task management with optimistic updates and error handling.
Existing Angular Example: Auto-refetching Service
examples/angular/auto-refetching/src/app/services/tasks.service.ts
Modified mutation onSuccess handlers to return the promise from query invalidation, allowing for better chaining and control flow.
Existing Angular Example: Optimistic Updates Component & Service
examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts, examples/angular/optimistic-updates/src/app/services/tasks.service.ts
Removed an unused mutation property. Refined type annotations and mutation lifecycle callbacks for improved clarity and explicitness in optimistic update handling.
Existing Angular Example: Mock API Interceptor
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
Updated error simulation for a specific endpoint to use an observable error instead of an HTTP error response, improving test realism.

Sequence Diagram(s)

Angular Unit Testing Example: Task Fetching and Mutation

sequenceDiagram
    participant User
    participant UnitTestingComponent
    participant TasksService
    participant MockInterceptor
    participant QueryClient

    User->>UnitTestingComponent: Loads app
    UnitTestingComponent->>TasksService: Fetch allTasks query
    TasksService->>MockInterceptor: GET /api/tasks
    MockInterceptor-->>TasksService: Return tasks array
    TasksService-->>UnitTestingComponent: Query result (tasks)

    User->>UnitTestingComponent: Add new task
    UnitTestingComponent->>TasksService: addTask mutation
    TasksService->>QueryClient: Cancel 'tasks' queries (optimistic update)
    TasksService->>MockInterceptor: POST /api/tasks
    MockInterceptor-->>TasksService: Return success or error
    TasksService->>QueryClient: Invalidate 'tasks' queries (refetch)
    QueryClient->>TasksService: Refetched tasks
    TasksService-->>UnitTestingComponent: Updated query result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Poem

In the garden of code where the test bunnies play,
New guides and examples have hopped in today.
With Jest and Angular, queries abound,
Mocked APIs hopping, no real bugs are found.
Optimistic updates and errors in tow—
This patch brings more carrots for testing to grow!
🥕🐇

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch clone-feat/docsAngularTesting

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@gemini-code-assist gemini-code-assist bot left a 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 @gandalf-repo, 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!

This pull request significantly enhances the Angular documentation by introducing a dedicated section on testing. It provides a comprehensive guide and a new, fully functional unit testing example project using Jest and Testing Library, demonstrating best practices for testing Angular applications with TanStack Query.

Highlights

  • New Testing Documentation: A new guide page (docs/framework/angular/guides/testing.md) has been added, providing detailed instructions and code examples for testing Angular applications, including how to handle signals, turn off retries, and mock network calls.
  • Comprehensive Unit Testing Example: A complete, standalone Angular unit testing example project (examples/angular/unit-testing/) has been introduced. It's configured with Jest and Testing Library, and includes a mock API interceptor, a service demonstrating optimistic updates, and a detailed test suite.
  • Documentation Navigation Updates: The navigation structure in docs/config.json has been updated to include links to the new testing guide and the unit testing example, making them easily discoverable within the documentation.
  • Refinements to Existing Examples: Existing Angular examples (auto-refetching and optimistic-updates) have been refined to ensure consistency and adherence to best practices, such as explicitly returning invalidateQueries results and improving type definitions in mutation callbacks.
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

  1. 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-test
Copy link

refacto-test bot commented Aug 10, 2025

🤖 Refacto.AI: PR Summary & Reviewer Guide

🎯 1. The Goal (Why was this PR raised?)

This PR aims to add comprehensive documentation and examples for testing Angular applications with TanStack Query. The goal is to provide developers with guidance on unit testing services that use TanStack Query in Angular applications.

🗺️ 2. The Changes (What was implemented?)

This section provides a walkthrough of the changes, connecting them to the PR's goals.

File Name Implementation Details Goal / Requirement Addressed
docs/framework/angular/guides/testing.md (Added) Added new documentation guide explaining how to test Angular services with TanStack Query, including code examples and best practices. Add Angular testing documentation
docs/config.json (Modified) Updated navigation configuration to include links to the new testing documentation and examples. Add navigation for new testing documentation
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (Added) Added test file for TasksService demonstrating how to test queries and mutations with TanStack Query. Provide testing example code
examples/angular/unit-testing/src/app/services/tasks.service.ts (Added) Added service implementation that will be tested, including query and mutation options. Provide service example for testing
examples/angular/unit-testing/src/app/components/unit-testing.component.ts (Added) Added component that uses the TasksService to demonstrate integration. Provide component example for testing
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (Added) Added HTTP interceptor to mock API responses for testing. Provide API mocking example
examples/angular/unit-testing/src/app/app.config.ts (Added) Added application configuration including HTTP client and TanStack Query setup. Configure example application
examples/angular/unit-testing/src/app/app.component.ts (Added) Added root component that includes the unit testing component. Setup example application
examples/angular/unit-testing/angular.json (Added) Added Angular CLI configuration file for the unit testing example project. Configure example project
examples/angular/unit-testing/package.json (Added) Added package.json with dependencies including testing libraries. Setup example project dependencies
examples/angular/unit-testing/tsconfig.json (Added) Added TypeScript configuration for the example project. Configure TypeScript for example
examples/angular/unit-testing/tsconfig.app.json (Added) Added application-specific TypeScript configuration. Configure TypeScript for example
examples/angular/unit-testing/tsconfig.spec.json (Added) Added test-specific TypeScript configuration. Configure TypeScript for testing
examples/angular/unit-testing/jest.config.ts (Added) Added Jest configuration for running tests. Configure Jest for testing
examples/angular/unit-testing/.eslintrc.cjs (Added) Added ESLint configuration file. Configure linting for example
examples/angular/unit-testing/.devcontainer/devcontainer.json (Added) Added dev container configuration for development environment. Configure development environment
examples/angular/unit-testing/README.md (Added) Added README with instructions for running the example. Provide documentation for example
examples/angular/unit-testing/src/index.html (Added) Added HTML entry point for the example application. Setup example application
examples/angular/unit-testing/src/main.ts (Added) Added main entry point for bootstrapping the Angular application. Setup example application
examples/angular/optimistic-updates/src/app/services/tasks.service.ts (Modified) Updated method signatures and return types for consistency with the new testing examples. Improve existing examples
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts (Modified) Updated error handling to use throwError instead of returning error response. Improve error handling in examples
examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts (Modified) Removed unused clearMutation. Clean up existing code
examples/angular/auto-refetching/src/app/services/tasks.service.ts (Modified) Updated onSuccess handlers to return the invalidateQueries call. Improve consistency in examples
pnpm-lock.yaml (Modified) Updated lock file with new dependencies. Update dependencies

🤔 3. Key Areas for Human Review

Here are the most important areas to focus your review on, including specific testing instructions.

Area of Concern: Testing Documentation Completeness

  • File: docs/framework/angular/guides/testing.md
  • Why: This is the primary documentation file that explains how to test Angular applications with TanStack Query. Its accuracy and completeness are crucial for developer experience.
  • Testing Instruction: Review the documentation for clarity, correctness, and completeness. Verify that it covers all important aspects of testing (setup, mocking, assertions) and that the code examples are correct and follow best practices.

Area of Concern: Test Implementation

  • File: examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (Lines 10-112)
  • Why: This file contains the core testing logic that demonstrates how to test queries and mutations with TanStack Query. It's essential that it provides a correct and comprehensive example.
  • Testing Instruction: Review the test implementation to ensure it properly tests both successful and failing scenarios for queries and mutations. Verify that it demonstrates proper setup, mocking, and assertions for TanStack Query in Angular.

Area of Concern: Mock Interceptor Implementation

  • File: examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
  • Why: The mock interceptor is crucial for testing as it simulates API responses without making actual network calls. Its implementation affects the reliability of tests.
  • Testing Instruction: Review the mock interceptor to ensure it properly handles different HTTP methods and provides appropriate responses. Check that it simulates both success and error scenarios correctly.

Area of Concern: Integration with Existing Documentation

  • File: docs/config.json (Lines 707-713, 1287-1294)
  • Why: This file integrates the new documentation into the existing navigation structure. Proper integration is important for discoverability.
  • Testing Instruction: Verify that the navigation links are correctly placed in the documentation structure and that they point to the correct paths. Check that the labels are clear and consistent with the rest of the documentation.

@gandalf-repo
Copy link
Author

/refacto-test

@refacto-test
Copy link

refacto-test bot commented Aug 10, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

@gemini-code-assist gemini-code-assist bot left a 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 valuable documentation and a new example for testing Angular applications with TanStack Query. The changes are well-structured and the new content is comprehensive. I've identified a few areas for improvement in the new documentation and example code to enhance correctness, type safety, and test reliability. My feedback includes fixing a syntax error in a code example, improving type safety by replacing any with more specific types, and addressing a state management issue in a mock interceptor that could lead to flaky tests.

injector = TestBed.inject(Injector);
});

it('should get all the Tasks', () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The test function is missing the async keyword. Since await is used on line 99, this will result in a syntax error. Please add async to the function definition to make it a valid asynchronous test.

Suggested change
it('should get all the Tasks', () => {
it('should get all the Tasks', async () => {

} from '@angular/common/http'
import type { Observable } from 'rxjs'

let callNumber = 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The callNumber variable is stateful and defined at the module level. This can lead to flaky tests because its value will persist across different tests in the same file if not reset. To ensure test isolation, this state should be managed within the tests. I recommend exporting a reset function from this module and calling it in a beforeEach block in your spec file.

let callNumber = 0;

export function resetCallNumber(): void {
  callNumber = 0;
}

});

it('should get all the Tasks', () => {
let allTasks: any;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any for allTasks is not ideal, especially in documentation that should promote best practices. The type CreateQueryResult is already imported on line 64 and can be used here to provide strong typing.

Suggested change
let allTasks: any;
let allTasks: CreateQueryResult<Array<string>, Error>;

// We await the first result from the query
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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a typo in the comment. "inteceptor" should be "interceptor".

Suggested change
expect(allTasks.data()).toEqual([]); // Considering that the inteceptor is returning [] at the first query request.
expect(allTasks.data()).toEqual([]); // Considering that the interceptor is returning [] at the first query request.

),
mutationKey: ['tasks'],
onSuccess: () => {},
onMutate: async ({ task }) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The task parameter in the onMutate callback is untyped. For better type safety and consistency with other examples in the repository, please provide an explicit type.

      onMutate: async ({ task }: { task: string }) => {


return previousTodos
},
onError: (_err, _variables, context) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The parameters for the onError callback are untyped, which defaults to any. To improve type safety and code clarity, it's best to provide explicit types for them. The context, for instance, will be the data returned from onMutate.

      onError: (
        _err: any,
        _variables: { task: string; failMutation: boolean },
        context: Array<string> | undefined,
      ) => {

let service!: TasksService;
let injector!: Injector;
let allTasks: CreateQueryResult<Array<string>, Error>;
let addTask: any;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any for the addTask variable reduces type safety. You can use ReturnType<typeof injectMutation> to get a more specific and accurate type without having to write out the full complex type of the mutation result.

Suggested change
let addTask: any;
let addTask: ReturnType<typeof injectMutation>;

@refacto-test
Copy link

refacto-test bot commented Aug 10, 2025

Code Review: Angular Testing Implementation

👍 Well Done
Comprehensive Test Coverage

Thorough testing of query and mutation states improves reliability.

Mock Interceptor Implementation

Properly simulates API responses for reliable testing.

📌 Files Processed
  • examples/angular/unit-testing/src/app/services/tasks.service.spec.ts
  • examples/angular/unit-testing/src/app/components/unit-testing.component.ts
  • examples/angular/unit-testing/src/app/services/tasks.service.ts
  • pnpm-lock.yaml
  • examples/angular/unit-testing/src/app/app.config.ts
  • examples/angular/unit-testing/angular.json
  • examples/angular/unit-testing/package.json
  • examples/angular/unit-testing/tsconfig.json
  • docs/framework/angular/guides/testing.md
  • examples/angular/unit-testing/src/index.html
  • examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts
  • examples/angular/unit-testing/.eslintrc.cjs
  • docs/config.json
  • examples/angular/unit-testing/src/app/app.component.ts
  • examples/angular/optimistic-updates/src/app/services/tasks.service.ts
  • examples/angular/unit-testing/tsconfig.app.json
  • examples/angular/unit-testing/jest.config.ts
  • examples/angular/unit-testing/tsconfig.spec.json
  • examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
  • examples/angular/unit-testing/README.md
  • examples/angular/unit-testing/src/main.ts
  • examples/angular/optimistic-updates/src/app/components/optimistic-updates.component.ts
  • examples/angular/auto-refetching/src/app/services/tasks.service.ts
  • examples/angular/unit-testing/.devcontainer/devcontainer.json
📝 Additional Comments
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (2)
Inconsistent Error Handling

Using hardcoded string 'CallNumber 2' creates brittle test dependent on mock implementation details. Test will break if mock implementation changes.

      const MOCK_TASK_NAME = 'CallNumber 2';
      await waitFor(() => expect(allTasks.data()).toEqual([task, MOCK_TASK_NAME]), {timeout: 2000});

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Invariant
Missing Cleanup Step

Missing afterEach cleanup for QueryClient can cause test state to leak between tests. Each test should start with a clean QueryClient state.

    afterEach(() => {
      queryClient.clear();
      sessionStorage.removeItem('unit-testing-tasks');
    });

Standards:

  • ISO-IEC-25010-Reliability-Recoverability
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • SRE-Resource-Management
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (2)
Mock Response Delay

Fixed 1-second delay in mock responses slows tests unnecessarily. Faster tests improve developer experience and CI/CD pipeline efficiency.

of(new HttpResponse({ status, body })).pipe(delay(100))

Standards:

  • ISO-IEC-25010-Performance-Time-Behaviour
  • Google-Performance-Best-Practices
Error Disclosure Risk

Generic error message could expose implementation details in production. Attackers could use error messages to gather information about the system.

    return throwError(() => new Error('Request failed')).pipe(delay(1000));

Standards:

  • CWE-209
  • OWASP-A07

Comment on lines +69 to +71
onError: () => {
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Error Handling

Empty onError callback prevents proper error handling during mutation testing. Failed mutations would silently fail without verification, reducing test reliability.

Suggested change
onError: () => {
}
});
onError: (error) => {
expect(error).toBeTruthy();
fail('Should not reach error state in success test');
}
Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • SRE-Error-Handling

Comment on lines +78 to +80
onSettled: () => {
return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query Cache Invalidation

Unconditional cache invalidation on every mutation causes unnecessary refetches. This creates network overhead and potential UI flashing when mutations are frequent.

Suggested change
onSettled: () => {
return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
},
onSuccess: () => {
return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
},
onError: (_err, _variables, context) => {
if (context) {
// Rollback the optimistic update
this.#queryClient.setQueryData<Array<string>>(['tasks'], context)
}
}
Standards
  • ISO-IEC-25010-Performance-Resource-Utilization
  • Netflix-Hot-Path-Optimization
  • Google-Performance-Best-Practices


it('should manage all tasks, add task, remove task', async () => {
// We await the first result from the query
await waitFor(() => expect(allTasks.isFetching()).toBe(false), {timeout: 10000});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excessive Timeout Value

Excessive timeout of 10 seconds for test assertions can mask performance issues and slow down test suite execution. Tests should fail quickly if conditions aren't met.

Suggested change
await waitFor(() => expect(allTasks.isFetching()).toBe(false), {timeout: 10000});
await waitFor(() => expect(allTasks.isFetching()).toBe(false), {timeout: 2000});
Standards
  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • SRE-Performance-Efficiency

let service!: TasksService;
let injector!: Injector;
let allTasks: CreateQueryResult<Array<string>, Error>;
let addTask: any;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Untyped Variable Declaration

Using 'any' type bypasses TypeScript's type checking, potentially causing runtime errors. Type safety ensures reliable test execution and prevents type-related failures.

Suggested change
let addTask: any;
let addTask: ReturnType<typeof injectMutation>;
Standards
  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Precondition

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (29)
examples/angular/unit-testing/.devcontainer/devcontainer.json (1)

1-4: Pin image more tightly and add minimal dev conveniences (optional).

Consider pinning to a digest or specific variant and adding basic tools to improve DX.

 {
   "name": "Node.js",
-  "image": "mcr.microsoft.com/devcontainers/javascript-node:22"
+  "image": "mcr.microsoft.com/devcontainers/javascript-node:22-bookworm",
+  "customizations": {
+    "vscode": {
+      "extensions": [
+        "dbaeumer.vscode-eslint",
+        "angular.ng-template",
+        "firsttris.vscode-jest-runner"
+      ]
+    }
+  },
+  "postCreateCommand": "npm ci"
 }
examples/angular/unit-testing/.eslintrc.cjs (1)

1-6: Add Jest/Testing Library overrides and ignore patterns.

This keeps the example lintable and avoids noise for build artifacts. Optional but recommended.

 // @ts-check
 
 /** @type {import('eslint').Linter.Config} */
-const config = {}
+const config = {
+  root: true,
+  ignorePatterns: ['dist/', 'coverage/'],
+  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
+  plugins: ['@typescript-eslint'],
+  overrides: [
+    {
+      files: ['**/*.spec.ts'],
+      env: { jest: true },
+      plugins: ['jest', 'testing-library'],
+      extends: ['plugin:jest/recommended', 'plugin:testing-library/angular'],
+    },
+  ],
+}
 
 module.exports = config
examples/angular/unit-testing/src/app/app.config.ts (2)

12-12: Import isDevMode to conditionally enable Devtools

Gate devtools to dev-only to avoid overhead in prod.

-import type { ApplicationConfig } from '@angular/core'
+import { isDevMode, type ApplicationConfig } from '@angular/core'

17-26: Enable TanStack Query Devtools only in dev mode

This keeps prod lean while preserving DX locally.

-    provideTanStackQuery(
-      new QueryClient({
-        defaultOptions: {
-          queries: {
-            gcTime: 1000 * 60 * 60 * 24, // 24 hours
-          },
-        },
-      }),
-      withDevtools(),
-    ),
+    provideTanStackQuery(
+      new QueryClient({
+        defaultOptions: {
+          queries: {
+            gcTime: 1000 * 60 * 60 * 24, // 24 hours
+          },
+        },
+      }),
+      ...(isDevMode() ? [withDevtools()] : []),
+    ),
examples/angular/unit-testing/src/app/app.component.ts (1)

8-9: Prefer explicit open/close tags over self-closing for custom components

Safer across linters/parsers and consistent with Angular style.

-  template: `<unit-testing />`,
+  template: `<unit-testing></unit-testing>`,
examples/angular/unit-testing/package.json (1)

21-21: Use a caret for zone.js to receive patch updates

Pinning to 0.15.0 may miss security/bug fixes.

-    "zone.js": "0.15.0"
+    "zone.js": "^0.15.0"
examples/angular/unit-testing/src/app/interceptor/mock-api.interceptor.ts (2)

18-43: Avoid global, sticky state across tests or provide a reset hook.

callNumber is module-scoped and will persist across tests/specs within the same process. This can cause order-dependent flakes. Consider exporting a test-only reset helper so suites can start from a clean slate.

 let callNumber = 0;
 
 export const mockInterceptor: HttpInterceptorFn = (
   req: HttpRequest<unknown>,
   next: HttpHandlerFn,
 ): Observable<HttpEvent<any>> => {
@@
 }
+
+// Test-only utility to reset interceptor state between tests
+// (can be tree-shaken away in prod builds if not imported)
+export function __resetMockApiState__(): void {
+  callNumber = 0
+  try {
+    sessionStorage.removeItem('unit-testing-tasks')
+  } catch {}
+}

If adopted, call __resetMockApiState__() in your spec beforeEach.


24-26: Consider making mock latency configurable to speed up tests.

A hard-coded 1000ms delay slows the suite. Allow overriding via a header or lower the default (e.g., 50–100ms) for faster tests while keeping behavior.

For example:

-  const respondWith = (status: number, body: any) =>
-    of(new HttpResponse({ status, body })).pipe(delay(1000))
+  const delayMs = Number(req.headers.get('x-mock-delay') ?? '1000')
+  const respondWith = (status: number, body: any) =>
+    of(new HttpResponse({ status, body })).pipe(delay(delayMs))

Then tests can set headers: { 'x-mock-delay': '0' } for near-instant responses.

examples/angular/optimistic-updates/src/app/services/tasks.service.ts (3)

50-50: Remove no-op onSuccess for clarity.

onSuccess: () => {} is redundant since onSettled handles invalidation. Dropping it reduces noise.

-      mutationKey: ['tasks'],
-      onSuccess: () => {},
+      mutationKey: ['tasks'],

57-67: Naming nit: prefer domain-consistent variable names.

previousTodos doesn’t match the “tasks” domain. Rename to previousTasks for clarity.

-        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

71-75: Tighten types for error callback.

Type the context to the snapshot type for safer rollback and self-documenting code.

-      onError: (_err: any, _variables: any, context: any) => {
+      onError: (_err: unknown, _variables: { task: string; failMutation: boolean }, context?: Array<string>) => {
         if (context) {
           this.#queryClient.setQueryData<Array<string>>(['tasks'], context)
         }
       },
examples/angular/unit-testing/src/app/components/unit-testing.component.ts (1)

39-41: Minor: trim trailing space in date format.

The format string includes a trailing space which may render as extra whitespace.

-          Updated At: {{ tasks.dataUpdatedAt() | date: 'MMMM d, h:mm:ss a ' }}
+          Updated At: {{ tasks.dataUpdatedAt() | date: 'MMMM d, h:mm:ss a' }}
examples/angular/unit-testing/src/app/services/tasks.service.spec.ts (2)

19-33: Optional: clear storage/reset interceptor state between tests.

To ensure order-independent, reproducible tests, clear sessionStorage in beforeEach or call a reset helper from the interceptor (if added).

 beforeEach(() => {
+  // Ensure a clean slate for each test
+  try { sessionStorage.removeItem('unit-testing-tasks') } catch {}
   TestBed.configureTestingModule({
     providers: [
       provideHttpClient(withFetch(), withInterceptors([mockInterceptor])),

If you adopt __resetMockApiState__, call it here instead.


14-15: Type the mutation handle for better IntelliSense.

addTask: any can be strongly typed using the library’s mutation result type to surface state/helpers accurately.

-    let addTask: any;
+    import type { CreateMutationResult } from '@tanstack/angular-query-experimental';
+    let addTask: CreateMutationResult<any, Error, { task: string; failMutation: boolean }, Array<string> | undefined>;

Adjust generics to your exact response/context types if desired.

examples/angular/unit-testing/src/app/services/tasks.service.ts (4)

50-51: Remove no-op onSuccess for clarity (same rationale as the other service).

Since invalidation happens in onSettled, this can be omitted.

-      mutationKey: ['tasks'],
-      onSuccess: () => {},
+      mutationKey: ['tasks'],

51-70: Add typings to mutation lifecycle for safety and consistency.

Type the onMutate variables and onError context to match the cached data. Also consider typing the HTTP response.

-      onMutate: async ({ task }) => {
+      onMutate: async ({ task }: { task: string }) => {
@@
-      onError: (_err, _variables, context) => {
+      onError: (
+        _err: unknown,
+        _variables: { task: string; failMutation: boolean },
+        context?: Array<string>,
+      ) => {
         if (context) {
           // Rollback the optimistic update
           this.#queryClient.setQueryData<Array<string>>(['tasks'], context)
         }
       },

Optionally, type the POST response:

-          this.#http.post(
+          this.#http.post<{ status: 'success'; task: string }>(
             `/api/tasks${failMutation ? '-wrong-url' : ''}`,
             task,
           ),

52-54: Tiny comment grammar nit.

“refetch” → “refetches”.

-   * On success, invalidates and refetch the "tasks" query cache to update the task list.
+   * On success, invalidates and refetches the "tasks" query cache to update the task list.

61-67: Naming nit: align with domain.

As in the other service, prefer previousTasks over previousTodos.

-        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
docs/framework/angular/guides/testing.md (10)

101-101: Typo: “inteceptor” → “interceptor”.

-      expect(allTasks.data()).toEqual([]); // Considering that the inteceptor is returning [] at the first query request.
+      expect(allTasks.data()).toEqual([]); // Considering that the interceptor is returning [] at the first query request.

56-65: Remove unused imports from the test snippet.

inject and CreateQueryResult are not used and may confuse readers.

-import { Injector, inject, runInInjectionContext } from "@angular/core";
+import { Injector, runInInjectionContext } from "@angular/core";
@@
-import type { CreateQueryResult} from "@tanstack/angular-query-experimental";

26-31: Remove unused mutationOptions from the service snippet.

It’s not referenced in the example.

 import {
   QueryClient,
-  mutationOptions,
   queryOptions,
 } from '@tanstack/angular-query-experimental'

41-44: Docstring mismatch: the code returns a Promise, not an Observable.

Align the comment with the actual return type from lastValueFrom(...).

   /**
    * Fetches all tasks from the API.
-   * Returns an observable containing an array of task strings.
+   * Returns a Promise that resolves to an array of task strings.
    */
@@
       queryFn: () => {
-        return lastValueFrom(this.#http.get<Array<string>>('/api/tasks'));
+        return lastValueFrom(this.#http.get<string[]>('/api/tasks'))
       }

Also applies to: 49-51


6-6: Tighten wording and fix grammar around signals/polling.

-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.
+Since there’s no built‑in way to await a signal reaching a specific value, we’ll use polling in tests (instead of converting signals to observables and filtering with RxJS). For polling, you can use the Angular Testing Library.

14-14: Grammar: use backticks and gerund; clarify phrasing.

-Otherwise we recommend to use the toObservable feature from Angular.
+Otherwise, we recommend using Angular’s `toObservable` feature.

18-18: Grammar and clarity: “through function” → “through functions”.

-Because the recommendation is to use services that provide the Query options through function this is what we are going to do.
+Because we recommend services that expose query options via functions, that’s what we’ll implement here.

131-131: Speed up tests by reducing artificial latency in the interceptor.

A full second per request makes tests slow and flaky. 25–100ms is enough to simulate asynchrony.

-    of(new HttpResponse({ status, body })).pipe(delay(1000))
+    of(new HttpResponse({ status, body })).pipe(delay(50))
@@
-    return throwError(() => new Error('error')).pipe(delay(1000));
+    return throwError(() => new Error('error')).pipe(delay(50));

Also applies to: 157-157


71-88: Avoid cross-test pollution from sessionStorage.

Consider clearing the storage key in beforeEach to keep tests independent.

   beforeEach(() => {
+    sessionStorage.removeItem('unit-testing-tasks');
     TestBed.configureTestingModule({
       providers: [
         provideHttpClient(withFetch(), withInterceptors([mockInterceptor])),

168-171: Fix typos and tighten phrasing in “Testing Network Calls” section.

-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 the data, mock the requests. There are multiple ways to do this; we recommend using an Angular HTTP interceptor (see [Angular docs](https://angular.dev/guide/http/interceptors) for details).
+You can see the interceptor setup in the “Unit testing / Jest” example.
examples/angular/unit-testing/angular.json (1)

96-102: Sanity check: ensure Jest builder dependency is present.

Make sure @angular-builders/jest is added as a devDependency to match this builder reference.

If helpful, I can scan the repo for the Jest config and the package entry to confirm alignment.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5990e and cb6cea3.

⛔ 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 (4)
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.component.ts (1)
examples/angular/unit-testing/src/app/components/unit-testing.component.ts (1)
  • Component (10-67)
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.ts (1)
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 (10)
examples/angular/auto-refetching/src/app/services/tasks.service.ts (1)

41-42: Ignore async/await wrapper for onSuccess—current code already awaited

The global onSuccess you’ve defined via mutationOptions returns the promise from invalidateQueries, and TanStack Query v5 will await that before resolving mutateAsync. No additional async/await is needed here.

• File: examples/angular/auto-refetching/src/app/services/tasks.service.ts
• Lines: 41–42

No changes required.

Likely an incorrect or invalid review comment.

examples/angular/unit-testing/tsconfig.json (1)

1-32: Add Jest & Node types and switch to CommonJS in tsconfig.spec.json

The current examples/angular/unit-testing/tsconfig.spec.json only sets "types": ["jest"] and inherits the ES2022 module from the base config. For Jest (ts-jest / jest-preset-angular) you should:

  • Override module to "CommonJS"
  • Include both Jest and Node types

Update examples/angular/unit-testing/tsconfig.spec.json as follows:

 {
   "extends": "./tsconfig.json",
   "compilerOptions": {
-    "outDir": "./out-tsc/spec",
-    "types": ["jest"]
+    "outDir": "./out-tsc/spec",
+    "module": "CommonJS",
+    "types": ["jest", "node"]
   },
   "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
 }

Likely an incorrect or invalid review comment.

examples/angular/unit-testing/tsconfig.app.json (1)

1-9: LGTM

App tsconfig looks standard for a standalone-bootstrap Angular example. No issues found.

examples/angular/unit-testing/src/main.ts (1)

1-5: LGTM

Entrypoint correctly bootstraps the standalone app with the provided ApplicationConfig.

docs/config.json (1)

710-713: ✅ Angular “Testing” guide entry verified

The slug in docs/config.json correctly points to an existing page:

  • docs/config.json (lines 710–713)
  • Target file: docs/framework/angular/guides/testing.md

Navigation won’t break—approving this change.

examples/angular/unit-testing/src/index.html (1)

1-13: HTML scaffold — LGTM

Minimal and correct for an Angular example root document.

examples/angular/optimistic-updates/src/app/services/tasks.service.ts (1)

78-79: Good: return invalidate promise from onSettled.

Returning the invalidateQueries promise helps upstream await cache refresh. Matches recommended patterns.

examples/angular/unit-testing/src/app/components/unit-testing.component.ts (1)

10-47: Solid example component using injectQuery/injectMutation.

Template clearly surfaces loading/fetching states; logic is straightforward. No issues spotted.

examples/angular/unit-testing/src/app/services/tasks.service.ts (1)

22-28: LGTM: query setup is clear and returns a Promise as expected.

Using lastValueFrom to bridge to a Promise aligns with queryFn expectations.

docs/framework/angular/guides/testing.md (1)

8-12: No changes needed for the Angular Testing Library installation

The @testing-library/angular package does support the ng add schematic (it also installs @testing-library/dom), so the existing:

ng add @testing-library/angular

is correct as-is.

Comment on lines +1292 to 1294
"label": "Unit Testing / Jest",
"to": "framework/angular/examples/unit-testing"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Angular "Unit Testing / Jest" example — looks good; verify example page and code exist

Great addition. Let’s ensure both the docs page and the example project are present.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking for Angular Unit Testing example doc page..."
fd -a -i --type f 'unit-testing\.(md|mdx|tsx|jsx)' 2>/dev/null | rg -n 'framework/angular/examples' || {
  echo "Missing doc page for slug framework/angular/examples/unit-testing"
  exit 1
}

echo "Checking example project folder and spec file..."
fd -a -i 'examples/angular/unit-testing' >/dev/null
fd -a -i 'examples/angular/unit-testing/src/app/services/tasks.service.spec.ts' >/dev/null

echo "OK: Example page and project detected."

Length of output: 374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Listing all docs files and directories with 'unit-testing' in their paths under docs/"
fd -ai 'unit-testing' docs

echo ""
echo "Verifying example project folder:"
if fd -t d 'unit-testing' examples/angular; then
  echo "✔ Example directory found: examples/angular/unit-testing"
else
  echo "✖ Missing examples/angular/unit-testing directory"
fi

echo ""
echo "Verifying spec file exists:"
if [[ -f "examples/angular/unit-testing/src/app/services/tasks.service.spec.ts" ]]; then
  echo "✔ Spec file found"
else
  echo "✖ Missing spec: examples/angular/unit-testing/src/app/services/tasks.service.spec.ts"
fi

Length of output: 716


Missing Angular “Unit Testing / Jest” docs page

Our verification shows:

  • ✔ Example project directory exists at examples/angular/unit-testing/
  • ✔ Spec file present at examples/angular/unit-testing/src/app/services/tasks.service.spec.ts
  • ✖ No documentation page found under docs/framework/angular/examples/unit-testing.*

Please add the corresponding docs page (e.g. docs/framework/angular/examples/unit-testing.md or .mdx) so that the config.json entry under "framework/angular/examples/unit-testing" points to a real file.

🤖 Prompt for AI Agents
In docs/config.json around lines 1292 to 1294, the entry for "Unit Testing /
Jest" under "framework/angular/examples/unit-testing" points to a documentation
page that does not exist. To fix this, create a new documentation file named
unit-testing.md or unit-testing.mdx in the docs/framework/angular/examples/
directory that covers the Angular unit testing example, ensuring the config.json
link points to this new file.

Comment on lines +90 to +103
it('should get all the Tasks', () => {
let allTasks: any;
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});
expect(allTasks.status()).toEqual('success');
expect(allTasks.data()).toEqual([]); // Considering that the inteceptor is returning [] at the first query request.
// To have a more complete example have a look at "unit testing / jest"
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Make the test async to allow await (copy-paste fix).

You’re using await inside the test body, but it(...) isn’t marked async.

-    it('should get all the Tasks', () => {
+    it('should get all the tasks', async () => {
📝 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.

Suggested change
it('should get all the Tasks', () => {
let allTasks: any;
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});
expect(allTasks.status()).toEqual('success');
expect(allTasks.data()).toEqual([]); // Considering that the inteceptor is returning [] at the first query request.
// To have a more complete example have a look at "unit testing / jest"
});
it('should get all the tasks', async () => {
let allTasks: any;
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});
expect(allTasks.status()).toEqual('success');
expect(allTasks.data()).toEqual([]); // Considering that the inteceptor is returning [] at the first query request.
// To have a more complete example have a look at "unit testing / jest"
});
🤖 Prompt for AI Agents
In docs/framework/angular/guides/testing.md around lines 90 to 103, the test
function uses `await` but the `it` callback is not marked as `async`. To fix
this, add the `async` keyword before the callback function in the `it` block
declaration so that `await` can be used properly inside the test.

Comment on lines +55 to 56
return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Same here: await invalidation for clear-all.

Aligns semantics with addTask and ensures tests observe a refetched cache.

-      onSuccess: () => {
-        return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
-      },
+      onSuccess: async () => {
+        await this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
+      },
📝 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.

Suggested change
return this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
},
onSuccess: async () => {
await this.#queryClient.invalidateQueries({ queryKey: ['tasks'] })
},
🤖 Prompt for AI Agents
In examples/angular/auto-refetching/src/app/services/tasks.service.ts around
lines 55 to 56, the call to invalidateQueries is not awaited, which can cause
inconsistent cache state observation in tests. Fix this by adding the await
keyword before this.#queryClient.invalidateQueries to ensure the invalidation
completes before proceeding, aligning with the addTask method's behavior.

Comment on lines 8 to +9
import { HttpResponse } from '@angular/common/http'
import { delay, of } from 'rxjs'
import { delay, of, throwError } from 'rxjs'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Add missing HttpErrorResponse import (and keep style consistent).

To support the change above, import HttpErrorResponse alongside HttpResponse. Also consider removing the lone semicolon at Line 49 to match the file’s no-semi style.

-import { HttpResponse } from '@angular/common/http'
+import { HttpResponse, HttpErrorResponse } from '@angular/common/http'

Search for code/tests expecting HttpErrorResponse shape (status, message) to confirm this aligns with consumers:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Scanning for patterns that assume HttpErrorResponse shape..."
rg -n --glob 'examples/angular/**' \
  'HttpErrorResponse|error\.status|instanceof\s+HttpErrorResponse|catchError\(' -A 3

Length of output: 270


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and display the mock API interceptor file around the relevant import and line 49
file=$(fd --type f mock-api.interceptor.ts | head -n1)
echo "File: $file"
echo "----- Lines 1-60 -----"
sed -n '1,60p' "$file"
echo "----- Lines 40-80 -----"
sed -n '40,80p' "$file"

Length of output: 2219


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Display the import statements and around line 49 for the optimistic-updates example
file="examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts"
echo "File: $file"
echo "----- Lines 1-20 (imports) -----"
sed -n '1,20p' "$file"
echo "----- Lines 40-60 -----"
sed -n '40,60p' "$file"

Length of output: 1543


Remove the unnecessary import suggestion and fix the trailing semicolon

The file doesn’t reference HttpErrorResponse anywhere, so you can skip adding that import. However, there’s a lone semicolon on the throwError return that should be removed to match the file’s no-semi style.

• File: examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
• Around line ~49:

-return throwError(() => new Error('error')).pipe(delay(1000));
+return throwError(() => new Error('error')).pipe(delay(1000))
📝 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.

Suggested change
import { HttpResponse } from '@angular/common/http'
import { delay, of } from 'rxjs'
import { delay, of, throwError } from 'rxjs'
return throwError(() => new Error('error')).pipe(delay(1000))
🤖 Prompt for AI Agents
In
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
around lines 8 to 9 and near line 49, remove the unnecessary import of
HttpErrorResponse since it is not used in the file. Also, locate the throwError
return statement around line 49 and remove the trailing semicolon to comply with
the file's no-semicolon style.

return respondWith(500, {
status: 'error',
})
return throwError(() => new Error('error')).pipe(delay(1000));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Emit HttpErrorResponse instead of a generic Error for realistic HttpClient errors and stronger typing.

Returning a plain Error loses status/URL/context that many handlers and tests depend on (e.g., checking error.status). Prefer HttpErrorResponse to accurately simulate backend failures.

-    return throwError(() => new Error('error')).pipe(delay(1000));
+    return throwError(() => new HttpErrorResponse({
+      status: 500,
+      statusText: 'Server Error',
+      url: req.url,
+      error: { status: 'error' },
+    })).pipe(delay(1000))

Note: This change requires importing HttpErrorResponse (see next comment).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
examples/angular/optimistic-updates/src/app/interceptor/mock-api.interceptor.ts
at line 49, replace the generic Error thrown by throwError with an instance of
HttpErrorResponse to simulate realistic HttpClient errors. This change preserves
HTTP status, URL, and context information that downstream handlers and tests
rely on. Import HttpErrorResponse from @angular/common/http and construct it
with appropriate properties such as status and statusText before passing it to
throwError.

Comment on lines +5 to +7
- `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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Include equivalent test commands for all package managers.

Right now only the npm test command is documented. Add yarn/pnpm/bun equivalents for consistency with the install/start bullets.

- - `npm run test` to run the tests
+ - `npm run test` or `yarn test` or `pnpm test` or `bun test` to run the tests

Quick check to ensure start and test scripts exist in the example’s package.json:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

PKG="examples/angular/unit-testing/package.json"
if [[ ! -f "$PKG" ]]; then
  echo "Not found: $PKG"
  exit 1
fi

echo "Scripts in $PKG:"
jq -r '.scripts' "$PKG"

echo
echo "Expecting both \"start\" and \"test\" script entries..."
jq -er '.scripts.start' "$PKG" >/dev/null && echo "start: OK" || { echo "start: MISSING"; exit 1; }
jq -er '.scripts.test'  "$PKG" >/dev/null && echo "test:  OK" || { echo "test:  MISSING"; exit 1; }

Length of output: 758


Add missing test commands for Yarn, pnpm, and Bun in README

The test script is defined in examples/angular/unit-testing/package.json, so we should list all package‐manager equivalents for consistency with the install/start steps.

• File: examples/angular/unit-testing/README.md
• Lines: 5–7

- - `npm run test` to run the tests
+ - `npm run test` or `yarn test` or `pnpm test` or `bun test` to run the tests
📝 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.

Suggested change
- `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`
- `npm run test` or `yarn test` or `pnpm test` or `bun test` to run the tests
🤖 Prompt for AI Agents
In examples/angular/unit-testing/README.md around lines 5 to 7, the test command
is only listed for npm. Add the equivalent test commands for Yarn, pnpm, and Bun
to match the style used for install and start commands. Update the third line to
include "yarn test", "pnpm test", and "bun test" alongside "npm run test" for
consistency.

Comment on lines +45 to +53
const tasks = JSON.parse(
sessionStorage.getItem('unit-testing-tasks') || '[]',
)
tasks.push(req.body)
sessionStorage.setItem(
'unit-testing-tasks',
JSON.stringify(tasks),
)
return respondWith(201, {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix switch-case declaration scope (noSwitchDeclarations).

const tasks is declared directly under the case 'POST' label. Wrap the case body in a block to avoid leaking declarations across cases and to satisfy lint/correctness.

-      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,
+        })
+      }
📝 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.

Suggested change
const tasks = JSON.parse(
sessionStorage.getItem('unit-testing-tasks') || '[]',
)
tasks.push(req.body)
sessionStorage.setItem(
'unit-testing-tasks',
JSON.stringify(tasks),
)
return respondWith(201, {
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 45 to 53, the const declaration for tasks is directly under the
case 'POST' label, which can cause scope leakage across cases. To fix this, wrap
the entire case 'POST' body in curly braces to create a block scope, ensuring
the const declaration is scoped only within this case and preventing any
declaration leakage.

Comment on lines +57 to +76
// Add a task
const task = 'Task 1';
const doneMutation = addTask.mutateAsync({
task,
failMutation: false
}, {
onSuccess: (data: any, variables: any, _context: any) => {
expect(data).toEqual({
status: 'success',
task: task
});
},
onError: () => {
}
});

expect(allTasks.data()).toEqual([]);

await expect(doneMutation).resolves.toEqual({
status: 'success',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make optimistic update assertion deterministic.

Right after mutateAsync, asserting allTasks.data() equals [] is timing-sensitive because onMutate awaits cancelQueries before applying the optimistic update. Assert the optimistic value with waitFor instead.

-      const doneMutation = addTask.mutateAsync({
+      const doneMutation = addTask.mutateAsync({
         task,
         failMutation: false
       }, {
         onSuccess: (data: any, variables: any, _context: any) => {
           expect(data).toEqual({
             status: 'success',
             task: task
           });
         },
         onError: () => {
         }
       });
-
-      expect(allTasks.data()).toEqual([]);
+      // Wait until onMutate applies the optimistic update
+      await waitFor(() => expect(allTasks.data()).toEqual([task]), { timeout: 10000 });
 
       await expect(doneMutation).resolves.toEqual({
         status: 'success',
         task: 'Task 1'
       });
-      // With Optimistic update the value is already available even if all tasks has not been refetch yet.
-      expect(allTasks.data()).toEqual([task]);
+      // Still optimistic until invalidation refetches
+      expect(allTasks.data()).toEqual([task]);
📝 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.

Suggested change
// Add a task
const task = 'Task 1';
const doneMutation = addTask.mutateAsync({
task,
failMutation: false
}, {
onSuccess: (data: any, variables: any, _context: any) => {
expect(data).toEqual({
status: 'success',
task: task
});
},
onError: () => {
}
});
expect(allTasks.data()).toEqual([]);
await expect(doneMutation).resolves.toEqual({
status: 'success',
// Add a task
const task = 'Task 1';
const doneMutation = addTask.mutateAsync({
task,
failMutation: false
}, {
onSuccess: (data: any, variables: any, _context: any) => {
expect(data).toEqual({
status: 'success',
task: task
});
},
onError: () => {
}
});
// Wait until onMutate applies the optimistic update
await waitFor(() => expect(allTasks.data()).toEqual([task]), { timeout: 10000 });
await expect(doneMutation).resolves.toEqual({
status: 'success',
task: 'Task 1'
});
// Still optimistic until invalidation refetches
expect(allTasks.data()).toEqual([task]);
🤖 Prompt for AI Agents
In examples/angular/unit-testing/src/app/services/tasks.service.spec.ts between
lines 57 and 76, the test asserts that allTasks.data() equals [] immediately
after calling mutateAsync, which is timing-sensitive due to the asynchronous
nature of onMutate awaiting cancelQueries before applying the optimistic update.
To fix this, replace the immediate assertion with a waitFor call that waits
until allTasks.data() reflects the optimistic update, ensuring the assertion is
deterministic and not subject to race conditions.

Comment on lines +82 to +111
// We await the invalidation of the 'tasks' query cache to have worked
// We test here that the new cache is the one returned by the interceptor
// and no longer the optimistic cache.
await waitFor(() => expect(allTasks.data()).toEqual([task, 'CallNumber 2']), {timeout: 10000});

// Reset the mutation
addTask.reset();
expect(addTask.isPending()).toBe(false);

// Test a mutation error now
const taskError = 'Task 2';
const doneMutationError = addTask.mutateAsync({
task: taskError,
failMutation: true
}, {
onError: (data: any, _variables: any, _context: any) => {
expect(data).toEqual(new Error('error'));
}
});
// To test the optimistic update we need to wait for the mutation to be in progress
expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2']);
await waitFor(() => expect(addTask.isIdle()).toBe(false), {timeout: 10000});
await waitFor(() => expect(addTask.isPending()).toBe(false), {timeout: 10000});
// Now we have finished the optimistic update but before the error
expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2', taskError]);
await expect(doneMutationError).rejects.toThrow('error');
// We test here that the new cache is the one that was rolled back
// and no longer the optimistic cache.
expect(allTasks.data()).toEqual([task, 'CallNumber 2'])
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Stabilize failure-path assertions; avoid racing on mutation state flags.

Asserting “before the error” after isPending() becomes false is racy. Instead, explicitly wait for the optimistic state, then the rejection, then the rollback.

-      // Reset the mutation
+      // Reset the mutation
       addTask.reset();
       expect(addTask.isPending()).toBe(false);
 
       // Test a mutation error now
       const taskError = 'Task 2';
       const doneMutationError = addTask.mutateAsync({
         task: taskError,
         failMutation: true
       }, {
         onError: (data: any, _variables: any, _context: any) => {
           expect(data).toEqual(new Error('error'));
         }
       });
-      // To test the optimistic update we need to wait for the mutation to be in progress
-      expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2']);
-      await waitFor(() => expect(addTask.isIdle()).toBe(false), {timeout: 10000});
-      await waitFor(() => expect(addTask.isPending()).toBe(false), {timeout: 10000});
-      // Now we have finished the optimistic update but before the error
-      expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2', taskError]);
-      await expect(doneMutationError).rejects.toThrow('error');
-      // We test here that the new cache is the one that was rolled back
-      // and no longer the optimistic cache.
-      expect(allTasks.data()).toEqual([task, 'CallNumber 2'])
+      // Initial cache before mutation
+      expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2']);
+      // Wait for optimistic update to apply
+      await waitFor(
+        () =>
+          expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2', taskError]),
+        { timeout: 10000 },
+      );
+      // Then wait for the mutation to fail
+      await expect(doneMutationError).rejects.toThrow('error');
+      // Finally, verify rollback occurred
+      await waitFor(
+        () =>
+          expect(allTasks.data()).toEqual([task, 'CallNumber 2']),
+        { timeout: 10000 },
+      );
📝 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.

Suggested change
// We await the invalidation of the 'tasks' query cache to have worked
// We test here that the new cache is the one returned by the interceptor
// and no longer the optimistic cache.
await waitFor(() => expect(allTasks.data()).toEqual([task, 'CallNumber 2']), {timeout: 10000});
// Reset the mutation
addTask.reset();
expect(addTask.isPending()).toBe(false);
// Test a mutation error now
const taskError = 'Task 2';
const doneMutationError = addTask.mutateAsync({
task: taskError,
failMutation: true
}, {
onError: (data: any, _variables: any, _context: any) => {
expect(data).toEqual(new Error('error'));
}
});
// To test the optimistic update we need to wait for the mutation to be in progress
expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2']);
await waitFor(() => expect(addTask.isIdle()).toBe(false), {timeout: 10000});
await waitFor(() => expect(addTask.isPending()).toBe(false), {timeout: 10000});
// Now we have finished the optimistic update but before the error
expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2', taskError]);
await expect(doneMutationError).rejects.toThrow('error');
// We test here that the new cache is the one that was rolled back
// and no longer the optimistic cache.
expect(allTasks.data()).toEqual([task, 'CallNumber 2'])
});
// Reset the mutation
addTask.reset();
expect(addTask.isPending()).toBe(false);
// Test a mutation error now
const taskError = 'Task 2';
const doneMutationError = addTask.mutateAsync({
task: taskError,
failMutation: true
}, {
onError: (data: any, _variables: any, _context: any) => {
expect(data).toEqual(new Error('error'));
}
});
// Initial cache before mutation
expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2']);
// Wait for optimistic update to apply
await waitFor(
() =>
expect(queryClient.getQueryData(['tasks'])).toEqual([task, 'CallNumber 2', taskError]),
{ timeout: 10000 },
);
// Then wait for the mutation to fail
await expect(doneMutationError).rejects.toThrow('error');
// Finally, verify rollback occurred
await waitFor(
() =>
expect(allTasks.data()).toEqual([task, 'CallNumber 2']),
{ timeout: 10000 },
);
🤖 Prompt for AI Agents
In examples/angular/unit-testing/src/app/services/tasks.service.spec.ts around
lines 82 to 111, the test asserts mutation state flags in a way that can cause
race conditions, especially checking the optimistic update after isPending() is
false. To fix this, refactor the test to explicitly wait for the optimistic
update state before the mutation rejection, then await the rejection, and
finally verify the rollback state, ensuring each step completes before moving to
the next assertion.

Comment on lines +4 to +7
"outDir": "./out-tsc/spec",
"types": ["jest"]
},
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider adding @testing-library/jest-dom types for matcher IntelliSense.

If the tests use matchers like toBeInTheDocument, include jest-dom types to avoid TS errors and improve DX.

-      "types": ["jest"]
+      "types": ["jest", "@testing-library/jest-dom"]

Verify jest-dom is declared in the example’s package.json:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

PKG="examples/angular/unit-testing/package.json"
if [[ ! -f "$PKG" ]]; then
  echo "Not found: $PKG"
  exit 1
fi

echo "jest-dom version (if present):"
jq -r '.devDependencies["@testing-library/jest-dom"] // .dependencies["@testing-library/jest-dom"] // "NOT FOUND"' "$PKG"

Length of output: 362


Add jest-dom types for Testing Library matchers

To enable TypeScript support (IntelliSense and no TS errors) for common Testing Library matchers (e.g. toBeInTheDocument), update your tsconfig for specs:

• File: examples/angular/unit-testing/tsconfig.spec.json
• Section: compilerOptions.types

   "compilerOptions": {
-    "types": ["jest"]
+    "types": ["jest", "@testing-library/jest-dom"]
   }
📝 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.

Suggested change
"outDir": "./out-tsc/spec",
"types": ["jest"]
},
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
"outDir": "./out-tsc/spec",
- "types": ["jest"]
+ "types": ["jest", "@testing-library/jest-dom"]
},
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
🤖 Prompt for AI Agents
In examples/angular/unit-testing/tsconfig.spec.json around lines 4 to 7, the
compilerOptions.types array currently includes only "jest". To enable TypeScript
support for Testing Library matchers like toBeInTheDocument, add "jest-dom" to
the types array alongside "jest". This will provide IntelliSense and prevent
TypeScript errors related to Testing Library matchers in your spec files.

@arvi18 arvi18 closed this Aug 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants