angular / angular/angular

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

Open
#46,841 3 comments 2 reactions 0 assignees View on GitHub
area: testing P3
Dominant language
TypeScript
Stars
101k
Forks
27.5k
Avg merge
1d 19h
Merged PRs (30d)
288

Description

### 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](https://angular.io/guide/dynamic-component-loader#the-anchor-directive)) 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: '',
})
class TestHostComponent {
@ViewChild(FooDirective, { static: true }) fooDirective!: FooDirective;
}

describe('injected directive', () => {
let fixture: ComponentFixture;
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

```true
Not applicable
```

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

```true
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_

Contributor guide

Open the contributing guide

Research direction

Start with the reproduction in src/app/demo.cmpnt.spec.ts and the Angular core testing APIs used by DebugElement.query(By.directive). Reproduce the ng-template case, compare directive discovery with the working ViewChild lookup, and inspect the related core testing implementation. Done means a regression test demonstrates that directives on ng-template are discoverable through By.directive without breaking existing queries.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
frontend, testing
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.