angular: Running Jasmine tests: TypeError: Cannot read property 'nativeElement' of null

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x ] Bug report  
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

If you have an *ngIf on an element, you cannot get the element via -> fixture.debugElement.query(By.css(‘.welcome’));

I am even setting the value of welcome in the beforeEach() method and it still will not resolve to true on *ngIf=“welcome”

Expected behavior

*ngIf should resolve to true and element should be found and not null.

Minimal reproduction of the problem with instructions

I modified the Angular testing sample:

Please see the WelcomeComponent failure. https://plnkr.co/edit/txk3ZCOatFKqoRcjOofL?p=preview

To make it fail I added *ngIf to the H3 in welcome.component.ts. Without *ngIf it will not fail.

@Component({
  selector: 'app-welcome',
  template: '<h3 *ngIf="welcome" class="welcome" ><i>{{welcome}}</i></h3>'
})

In the welcome.component.spec.ts I set the value of welcome so the *ngIf="welcome" shoudl resolve to true.

userService = fixture.debugElement.injector.get(UserService);
componentUserService = userService;
// UserService from the root injector
userService = TestBed.get(UserService);

**comp.welcome = 'test';**

//  get the "welcome" element by CSS selector (e.g., by class name)
de = fixture.debugElement.query(By.css('.welcome'));
el = de.nativeElement;

What is the motivation / use case for changing the behavior?

Environment


@angular/cli: 1.4.1
node: 8.2.1
os: win32 x64
@angular/animations: 4.3.6
@angular/common: 4.3.6
@angular/compiler: 4.3.6
@angular/compiler-cli: 4.3.6
@angular/core: 4.3.6
@angular/forms: 4.3.6
@angular/http: 4.3.6
@angular/platform-browser: 4.3.6
@angular/platform-browser-dynamic: 4.3.6
@angular/platform-server: 4.3.6
@angular/router: 4.3.6
@angular/cli: 1.4.1
: 1.5.0
typescript: 2.4.1

Browser:
- [x ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
 node: 8.2.1
Windows

Others:
See the modified Angular testing plunkr I created.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 1
  • Comments: 22 (2 by maintainers)

Most upvoted comments

Why is this closed? I just started Unit Testing in Angular 5 and this issue immediately presents itself ie

it('should show subscription section', () => {
    fixture.detectChanges();
    const el = fixture.debugElement.query(By.css('#subscription-section')).nativeElement;
    expect(el).toBeTruthy();
  });

Was there ever a suitable resolution for this issue?

Fast forward several months and it’s still prevalent and causing me issues (Angular 5, Karma 1.7.1 and Jasmine 2.8.0)

Thanks

Sorry for the late reply.

Resolution:-

it(‘productSelection’, async(() => { spyOn(component, ‘productSelection’); const btn = fixture.debugElement.query(By.css(‘.BPNormal’)); btn.triggerEventHandler(‘click’, ‘productSelection’); fixture.whenStable().then(() => { expect(component.productSelection).toHaveBeenCalled(); }); }));

On Fri, Dec 7, 2018 at 6:32 PM choubani amir notifications@github.com wrote:

Could you share your solution please ?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/angular/angular/issues/19292#issuecomment-445226028, or mute the thread https://github.com/notifications/unsubscribe-auth/Ano3b6k-05QQx5QNC4liH_sJAFv2HgVnks5u2mb0gaJpZM4Pd7PZ .

Workaround If you are using *ngIf in the element, use hidden instead. <h2 [hidden]="hideItem"> My Message</h2>

This error is caused when jasmine could not find that element in the DOM. The most common scenario is using *ngIf in the template. According to docs, *ngIf destroys the element from DOM, if the expression evaluates to false.

Why is this closed? This is still a problem Friday Jan 25, 2019

Hello. I solved this problem by using fakeAsync call.

describe('validate Siret ', () => {
            it('should call the method validateSiret() when the blur event is triggered', () => {
                fakeAsync(() => {
                    spyOn(comp, 'validateSiret');
                    fixture.detectChanges();
                    const input: ElementRef = debugElement.query(By.css('#field_cc'));
                    input.nativeElement.blur();
                    tick();
                    expect(comp.validateSiret).toHaveBeenCalled();
                });
            });
        });

@jrmcdona - after setting comp.welcome = ‘test’; - try using fixture.detectChanges() in test suite. This may help you, as by default, Test components don’t run change detection automatically. To enable auto change detection - use fixture.autoDetectChanges() in beforeEach function.

I’ve found out what was my issue: the element I was trying to get wasn’t defined in the template at the moment that I tried to get it. In my case, I was trying to get a button inside a td, but my table was empty because I didn’t populate it with mock data.

Using a debugger, I could see that fakeAsync() and async() just make the compiler keep waiting for something that never comes, until the testing process ends and makes it seem like the test passed, but in reality it just didn’t run.

This issue is closed by the OP him/herself, feel free to open a new issue with minimal reproduction.

All, if using change-detection OnPush on the component, refer this ancient issue https://github.com/angular/angular/issues/12313 . In short, when using OnPush in the component, let the constructor’s ChangeDetectorRef be public. In the test, when you change a component’s member, do component.changeDetector.detectChanges()