Skip to content

NG 21 + Vitest + Non-stadanlone component with async pipe #65665

Open

Description

@Scipionh

Which @angular/* package(s) are the source of the bug?

common

Is this a regression?

Yes

Description

With Angular 21, I can't test (with vitest) a non-standalone component using the Async pipe. I get the following error:

X [ERROR] NG8004: No pipe found with name 'async'.
To fix this, import the "AsyncPipe" class from "@angular/common" and add it to the "imports" array of the module declaring the component. [plugin angular-compiler]                                                                                                                                                                 

    src/app/async-test/async-test.html:1:9:
      1 │ <p>{{v | async }}</p>
        ╵          ~~~~~                                                                                                                                          

  Error occurs in the template of component AsyncTestComponent.

    src/app/async-test/async-test.ts:6:15:
      6 │   templateUrl: './async-test.html',
        ╵                ~~~~~~~~~~~~~~~~~~~     

Here is the full code:

Test

describe('AsyncTestComponent', () => {
  let component: AsyncTestComponent;
  let fixture: ComponentFixture<AsyncTestComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [CommonModule, AsyncPipe ],
      declarations: [AsyncTestComponent]
    })
    .compileComponents();

    fixture = TestBed.createComponent(AsyncTestComponent);
    component = fixture.componentInstance;
    await fixture.whenStable();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Component:

@Component({
  selector: 'app-async-test',
  templateUrl: './async-test.html',
  styleUrl: './async-test.css',
  standalone: false
})
export class AsyncTestComponent {
  protected readonly v = of(1);
}

HTML:

<p>{{v | async }}</p>

Please provide a link to a minimal reproduction of the bug

ng new --> add a non standalone component and use the async pipe in it then run ng test

Please provide the exception or error you saw

I should be able to test my non-stadanlone component (using AsyncPipe) in angular 21.

Please provide the environment you discovered this bug in (run ng version)

Angular CLI       : 21.0.0
Angular           : 21.0.0
Node.js           : 22.16.0
Package Manager   : npm 10.9.2
Operating System  : win32 x64

┌───────────────────────────┬───────────────────┬───────────────────┐
│ Package                   │ Installed Version │ Requested Version │
├───────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build            │ 21.0.0            │ ^21.0.0           │
│ @angular/cli              │ 21.0.0            │ ^21.0.0           │
│ @angular/common           │ 21.0.0            │ ^21.0.0           │
│ @angular/compiler         │ 21.0.0            │ ^21.0.0           │
│ @angular/compiler-cli     │ 21.0.0            │ ^21.0.0           │
│ @angular/core             │ 21.0.0            │ ^21.0.0           │
│ @angular/forms            │ 21.0.0            │ ^21.0.0           │
│ @angular/platform-browser │ 21.0.0            │ ^21.0.0           │
│ @angular/router           │ 21.0.0            │ ^21.0.0           │
│ rxjs                      │ 7.8.2             │ ~7.8.0            │
│ typescript                │ 5.9.3             │ ~5.9.2            │
│ vitest                    │ 4.0.13            │ ^4.0.8            │
└───────────────────────────┴───────────────────┴───────────────────

Anything else?

No response

Activity

  1. JoostK commented on Nov 26, 2025

    @JoostK
    Member

    This seems to be working as expected, although an exact reproduction is missing so I do not have the full picture here.

    To run tests, the application is built like it normally would. As such, the AsyncTestComponent component is AOT compiled and the compiler rightfully concludes that the async pipe usage is broken, since no corresponding NgModule would be available that imports AsyncPipe or CommonModule.

  2. added
    needs reproductionThis issue needs a reproduction in order for the team to investigate further
    on Nov 26, 2025
  3. Scipionh commented on Nov 26, 2025

    @Scipionh
    Author

    Here is a project where the problem occurs:

    https://stackblitz.com/edit/hefgnomh

    If I run

    ng serve (or ng build) there is no issue, and the application has the desired behavior.

    however if I run

    ng test

    ✘ [ERROR] NG8004: No pipe found with name 'async'.
    To fix this, import the "AsyncPipe" class from "@angular/common" and add it to the "imports" array of the module declaring the component. [plugin angular-compiler]
    
        src/app/app.html:1:24:
          1 │ Hello world:  {{title | async}}
            ╵                         ~~~~~
    
      Error occurs in the template of component App.
    
        src/app/app.ts:6:15:
          6 │   templateUrl: './app.html',
            ╵                ~~~~~~~~~~~~
    

    How can I make my test pass here ?

  4. JoostK commented on Nov 26, 2025

    @JoostK
    Member

    That repro reveals a classic pitfall of NgModules. In a non-test build the main.ts file is used as entry-point which imports app.module.ts, making the compiler aware of AppModule and its contribution to AppComponent. In the test build, however, neither main.ts nor app.module.ts is part of the compilation, as it's not imported from anywhere nor is it present in tsconfig.spec.ts#include.

  5. Scipionh commented on Nov 26, 2025

    @Scipionh
    Author

    I see, however I was under the assumption that the module created by my TestBed.configureTestingModule would be self sufficient.
    What would you say is the best way to fix things here ? Include the modules in my tsconfig.spec.ts ?

  6. added
    area: testingIssues related to Angular testing features, such as TestBed
    on Nov 26, 2025
  7. added this to the Backlog milestone on Nov 26, 2025
  8. JoostK commented on Nov 26, 2025

    @JoostK
    Member

    I was under the assumption that the module created by my TestBed.configureTestingModule would be self sufficient.

    That's for JIT (re)compiling the component, it is not taken into account during the AOT compilation.

    What would you say is the best way to fix things here ? Include the modules in my tsconfig.spec.ts ?

    Switch to standalone components :-) But yeah, having the same file in the compilation unit by using tsconfig.spec.json#includes would be the next best alternative.

  9. Scipionh commented on Nov 27, 2025

    @Scipionh
    Author

    Yeah, migrating to standalone is the plan.
    Unless, I missed something obvious, I went again through the whole testing documentation, and I really feel a caveat should be added to offer light on this particular issue. Adding modules to the tsconfig.spec.json feels completely counter-intuitive.

  10. alan-agius4 commented on Nov 27, 2025

    @alan-agius4
    Contributor

    To resolve this issue you could update the tsconfig as below:

    {
      "extends": "./tsconfig.json",
      "compilerOptions": {
        "outDir": "./out-tsc/spec",
        "types": ["vitest/globals"]
      },
      "include": ["src/**/*.ts"]
    }
    

    Alternatively, you could use JIT instead of AOT for tests.

  11. added
    area: docsRelated to the documentation
    and removed
    needs reproductionThis issue needs a reproduction in order for the team to investigate further
    on Dec 3, 2025
  12. modified the milestones: Backlog, needsTriage on Dec 3, 2025
  13. pshurygin commented on Feb 5, 2026

    @pshurygin

    Can someone please explain how this can be considered "working as intended" if it was clearly a working and widely used scenario with v20+karma, but it no longer works in v21+vitest? I don't think NgModule or non-standalone components support is dropped or even deprecated in v21, so I would expect this to still work without the full migration to drop NgModules in favour of standalone.

    I also didn't really understand this explanation:

    That repro reveals a classic pitfall of NgModules. In a non-test build the main.ts file is used as entry-point which imports app.module.ts, making the compiler aware of AppModule and its contribution to AppComponent. In the test build, however, neither main.ts nor app.module.ts is part of the compilation, as it's not imported from anywhere nor is it present in tsconfig.spec.ts#include.

    Why is the AppModule/AppComponent is even relevant in this discussion? As we see in the reproduction scenario, CommonModule(which exports async pipe) is explicitly imported into the TestingModule itself, so it's not clear why the compiler needs something else to make this pipe usable within this module.

  14. JeanMeche commented on Feb 5, 2026

    @JeanMeche
    Member

    The main difference is that Karma use JIT by default and Vitest uses AOT by default.

    Compilation assumptions are different.

  15. JoostK commented on Feb 5, 2026

    @JoostK
    Member

    As @JeanMeche mentions, Vitest vs Karma is not the main differentiator here, it's JIT vs AOT. When using Vitest with JIT compilation issues like the one reported won't occur, and vice versa when using AOT compiled builds for Karma you'd run into the same errors.

    Why is the AppModule/AppComponent is even relevant in this discussion? As we see in the reproduction scenario, CommonModule(which exports async pipe) is explicitly imported into the TestingModule itself, so it's not clear why the compiler needs something else to make this pipe usable within this module.

    TestBed is runtime-only infrastructure that the AOT-compiler doesn't take into account, and arguably can't take into account since TestBed redeclares component declarations. Since multiple TestBed interactions can redeclare components in different ways, there cannot be a single AOT compiled component definition. So, using the AOT compiler will compile the code as it normally would (i.e. for all @{Component,Directive,Pipe,NgModule,Injectable} decorated classes), which also means that non-standalone components require their NgModule to be present.

  16. pshurygin commented on Feb 5, 2026

    @pshurygin

    Thank you, this does make more sense now. I was under the impression that karma used AOT by default this whole time, as AOT has been the default compiler for the main application for 6 years now, but apparently that is not true. And so switching to v21 with Vitest also silently switches your tests from JIT to AOT, which was not obvious at all, and introduces all these module limitations.

    So what are the intended preconditions to run tests in AOT mode? Would this ever only be possible if you drop the NgModules and use standalone for all of the tested components?

  17. hlovdal commented on Oct 26, 2026

    @hlovdal

    Confirming that putting

    "aot:" false,

    into the configuration used by testing makes a lot of problems go away (Angular 21 project with very old roots).

    $ npx ng config | jq '.. | objects | select(has("architect")) | .architect.build.configurations.development.aot'
    false
    
    $ npx ng config | jq '.. | objects | select(has("architect")) | .architect.test.options.buildTarget'
    "myprojectt:build:development"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: docsRelated to the documentationarea: testingIssues related to Angular testing features, such as TestBed

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions