angular / angular

Deliver web apps with confidence πŸš€
https://angular.dev
MIT License
96.19k stars 25.46k forks source link

TestBed: Error: Directive SomePipe has no selector, please add it! #36427

Open james-schwartzkopf opened 4 years ago

james-schwartzkopf commented 4 years ago

🐞 bug report

Affected Package

The issue is caused by package @angular/core/testing ### Is this a regression? Yes, this worked in 8.2. ### Description When I have a Pipe in a library project that has a super class with a ngOnDestroy method, a TestBed that imports the library module fails with the error "Directive SomePipe has no selector, please add it!". This doesn't happen when the super class does not have an ngOnDestroy method, and it doesn't happen if the Pipe is included directly in the TestBed, or if the Module is part of the default app instead of a library project. ``` export abstract class SomeBase implements OnDestroy { /* * My real base class had a transform method, ect, but this seems to be * all that's needed to trigger it, and it wouldn't trigger without it */ ngOnDestroy() { } } @Pipe({ name: 'some' }) export class SomePipe extends SomeBase implements OnDestroy, PipeTransform { transform(value: unknown, ...args: unknown[]): unknown { return null; } // Is this needed, or will Ivy use the base class's ngOnDestroy without it?? // it's not needed to trigger the error ngOnDestroy() { super.ngOnDestroy(); } } ``` ``` beforeEach(async(() => { TestBed.configureTestingModule({ imports: [SomeLibModule], declarations: [ AppComponent ], }).compileComponents(); })); ``` ## πŸ”¬ Minimal Reproduction https://github.com/james-schwartzkopf/ng9-issues/tree/lib-pipe-issue ``` yarn ng build some-lib ng test ``` ## πŸ”₯ Exception or Error

Error: Directive SomePipe has no selector, please add it!
    at verifySemanticsOfNgModuleDef (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:39047:1)
    at http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:39010:1
    at 
    at verifySemanticsOfNgModuleDef (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:39004:1)
    at Function.get (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:38956:1)
    at R3TestBedCompiler.applyProviderOverridesToModule (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:2087:44)
    at R3TestBedCompiler.compileTestModule (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:2386:1)
    at R3TestBedCompiler.finalize (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:1880:1)
    at TestBedRender3.get testModuleRef [as testModuleRef] (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:3253:1)
    at TestBedRender3.inject (http://localhost:9877/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:3110:1)
## 🌍 Your Environment **Angular Version:**



$ ng version

 _                      _                 ____ _     ___
/ \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|

/ β–³ \ | ' \ / | | | | |/ _ | '| | | | | | | / _ | | | | (| | || | | (| | | | || |_ | | // __| ||_, |_,||_,|| __|__|| |/

Angular CLI: 9.1.0 Node: 12.16.1 OS: win32 x64

Angular: 9.1.0 ... animations, cli, common, compiler, compiler-cli, core, forms ... language-service, platform-browser, platform-browser-dynamic ... router Ivy Workspace: Yes

Package Version

@angular-devkit/architect 0.901.0 @angular-devkit/build-angular 0.901.0 @angular-devkit/build-ng-packagr 0.901.0 @angular-devkit/build-optimizer 0.901.0 @angular-devkit/build-webpack 0.901.0 @angular-devkit/core 9.1.0 @angular-devkit/schematics 9.1.0 @ngtools/webpack 9.1.0 @schematics/angular 9.1.0 @schematics/update 0.901.0 ng-packagr 9.1.0 rxjs 6.5.5 typescript 3.8.3 webpack 4.42.0

Anything else relevant?

AndrewKushnir commented 4 years ago

Hi @james-schwartzkopf, thanks for reporting the issue and providing a repro.

I performed additional investigation and found out that the SomeBase class doesn't have any Angular decorators, but has the ngOnDestroy lifecycle method and as a result, Ivy compiles it as if it has the base @Directive() decorator, see additional info here. As a result, the main Pipe class at runtime has both Directive and Pipe metadata. Since the base Directive has no selector defined, runtime checks that verify NgModule structure fail.

We will look into this problem more, but as a current solution, please add the @Pipe decorator (with some fake name field value, like @Pipe({ name: 'base-pipe-class' })) to the SomeBase class - it should resolve the problem.

Thank you.

JoostK commented 4 years ago

This looks suspect:

https://github.com/angular/angular/blob/0bf6e58db2e416603f75bf232b225008b82adeaf/packages/core/src/render3/jit/module.ts#L230-L236

The getDirectiveDef call finds the abstract directive as compiled by Ivy, but doesn't notice that the type is actually a pipe.

james-schwartzkopf commented 4 years ago

We will look into this problem more, but as a current solution, please add the @Pipe decorator (with some fake name field value, like @Pipe({ name: 'base-pipe-class' })) to the SomeBase class - it should resolve the problem.

Thank you.

Unfortunately I can't add the @Pipe because then I get ERROR: Cannot determine the module for class AsyncPipeBase. And since it's an abstract class I can't just add it to the module.

alxhub commented 4 years ago

@james-schwartzkopf, you can make the class non-abstract, and add it to the module that way. Or, as an alternative workaround, mark the abstract pipe with @Injectable().

sharshuv-quotient commented 1 year ago

I have the same issue, and my base class has the @Injectable decorator on it. The thing is this error happens only in my unit tests, not when actually running the app.

pburgmer commented 1 year ago

I have the same problem. Happens only during tests.

anektar commented 11 months ago

Same issue.. Why no update on this? I just implemented OnDestroy in my base class and instance class and immediatelly my tests fail...