angular icon indicating copy to clipboard operation
angular copied to clipboard

Unit testing: directives on ng-template present but not detectable with By.directive

Open jzabinski-dolios opened this issue 3 years ago • 2 comments

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

core

Is this a regression?

No

Description

Directives added to ng-template (as describe in Angular's guide to dynamic components) don't seem to be detectable using DebugElement.query(By.directive([directive])).

For example:

@Directive({
  selector: '[fooHost]',
})
class FooDirective {
  constructor(public viewContainerRef: ViewContainerRef) {}
}

@Component({
  template: '<ng-template fooHost></ng-template>',
})
class TestHostComponent {
  @ViewChild(FooDirective, { static: true }) fooDirective!: FooDirective;
}

describe('injected directive', () => {
  let fixture: ComponentFixture<TestHostComponent>;
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [FooDirective, TestHostComponent],
    }).compileComponents();
    fixture = TestBed.createComponent(TestHostComponent);
  });
  afterEach(() => {
    fixture.nativeElement.remove();
    // Get a fresh TestBed configuration between tests.
    TestBed.resetTestingModule();
  });
...

If the directive is queried, no directive will be found:

it('FooDirective undetectable using query(By.directive)', () => {
    fixture.detectChanges();
    const fooDirective = fixture.debugElement.query(By.directive(FooDirective));
    expect(fooDirective).toBeNull();
  });

Yet if we check the TestHostComponent's fooDirective, we can see that FooDirective was correctly added, and properties like its viewContainerRef have been defined:

it('FooDirective gets viewContainerRef', () => {
    const fooDirective = fixture.componentInstance.fooDirective;
    expect(fooDirective.viewContainerRef).toBeDefined();
  });

(Notice that fixture.detectChanges() was not necessary.)

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-unit-testing-examples-tpfzzf?file=src%2Fapp%2Fdemo.cmpnt.spec.ts

Please provide the exception or error you saw

Not applicable

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

This was documented in Stackblitz, where no console is available to run Angular's `ng version`. See the Dependencies in Stackblitz. Angular 14.0.6 was installed. It also appears locally in my older Angular setup:

Angular CLI: 13.3.3
Node: 16.13.0
Package Manager: npm 8.3.0
OS: darwin x64

Angular: 13.3.3
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1303.3
@angular-devkit/build-angular   13.3.3
@angular-devkit/core            13.3.3
@angular-devkit/schematics      13.3.3
@angular/fire                   7.3.0
@schematics/angular             13.3.3
rxjs                            6.6.7
typescript                      4.5.5

Anything else?

No response

jzabinski-dolios avatar Jul 14 '22 16:07 jzabinski-dolios

same problem, any solutions?

jqr91 avatar Jul 25 '22 17:07 jqr91

Isn't that pretty much expected ? Your component has no children.

Your ng-template points to nothing, it will not exist in the dom. But if you add a div with the directive, instantiate your template (with ngTemplateOutlet for example) it will work.

JeanMeche avatar Feb 05 '23 19:02 JeanMeche