DOM not updating in Jasmine

John Grayson

I have a simple component with a button that toggles the visibility of a paragraph on and off. The button toggles the visibility correctly in the app, but it does not toggle properly in my Jasmine unit test (the content does not toggle properly). It also does not work properly if I manually click the toggle button in the test browser.

Interestingly, I also have a passing test that tests my toggle method that sets my hideContent to false. However, even with hideContent: false, my content does not show up.

Relevant parts of my code:

alert-button-component.ts:

export class AlertButtonComponent implements OnInit {

  hideContent = true;

  constructor() { }

  ngOnInit(): void {
  }

  toggle() {
    this.hideContent = !this.hideContent;
  }
}

alert-button.component.html:

<div class="content">
    <p id="content" *ngIf="hideContent">My Content</p>
    <button (click) = "toggle()" class="button">Toggle Visibility</button>
</div>

alert-button.component.spec.ts:

describe('AlertButtonComponent', () => {
  let component: AlertButtonComponent;
  let fixture: ComponentFixture<AlertButtonComponent>;
  let de: DebugElement;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ AlertButtonComponent ]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(AlertButtonComponent);
    component = fixture.componentInstance;
    de = fixture.debugElement;
    fixture.detectChanges();
  });

 // Interestingly enough, this test works, but the content does not show up either
 it('should toggle', () => {
    expect(component.hideContent).toBeTruthy();
    component.toggle();
    expect(component.hideContent).toBeFalsy();
  });

  // returns TypeError: Cannot read property 'nativeElement' of null
  it('should show content after clicking button', () => {
    spyOn(component, 'toggle');
    const el = de.nativeElement;
    el.querySelector('button').dispatchEvent(new Event('click'));
    expect(component.toggle).toHaveBeenCalled();
    expect(de.query(By.css('#content')).nativeElement).toBeTruthy();
  });
});

Any help would greatly be appreciated!

AliF50

I have explained in the comments, it seems like you only need one line for both tests.

// Interestingly enough, this test works, but the content does not show up either
 it('should toggle', () => {
    expect(component.hideContent).toBeTruthy();
    component.toggle();
    fixture.detectChanges(); // to show the content, you have to call fixture.detectChanges() 
// for change detection to kick in to see the content. This is optional, like you said the test 
// already passses.
    expect(component.hideContent).toBeFalsy();
  });

  // returns TypeError: Cannot read property 'nativeElement' of null
  it('should show content after clicking button', () => {
    spyOn(component, 'toggle');
    const el = de.nativeElement;
    el.querySelector('button').dispatchEvent(new Event('click'));
    expect(component.toggle).toHaveBeenCalled();
    fixture.detectChanges(); // again, call fixture.detectChanges for reason stated above.
    // this time it is not optional
    expect(de.query(By.css('#content')).nativeElement).toBeTruthy();
  });

Edit

To debug your tests, I assume a browser opens when you're running npm run test.

When the browser opens, quickly press F12 (or inspect the dom) and it should trip on the debugger points. Press play to release the debuggers I think there is even a debug button as well depending on what version of Karma you're running.

  it('should show content after clicking button', () => {
    spyOn(component, 'toggle');
    const el = de.nativeElement;
    el.querySelector('button').dispatchEvent(new Event('click'));
    expect(component.toggle).toHaveBeenCalled();
    debugger; // you shouldn't see the p tag
    fixture.detectChanges(); // again, call fixture.detectChanges for reason stated above.
    // this time it is not optional
    expect(de.query(By.css('#content')).nativeElement).toBeTruthy();
    debugger; // you should see the p tag, maybe even go through the DOM tree to see it
  });

Another side note is that the first fixture.detectChanges in the first beforeEach calls ngOnInit so it is needed. The other fixture.detectChanges later on are what will change the view according to the change in state.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related