Home > Software design >  Testing Ionic Toast button click in Jasmine
Testing Ionic Toast button click in Jasmine

Time:05-20

I am unable to query for one of the Toast buttons inside while testing. It simply returns null. The class is set, and that is what is being used to query.

it('should make a call to retrieval method on retry', async () => {
      spyOn(component, 'retrieveEntry');

      await component.retryRetrieval();
      fixture.detectChanges();

      await fixture.whenStable();

      const retryButton = fixture.debugElement.query(By.css('.retry-button'));
      retryButton.nativeElement.click();
      fixture.detectChanges();

      expect(component.retrieveEntry).toHaveBeenCalled();
});

In the test results I can see the toast being created, with the class of .retry-button being set to the desired button.

I am stumped, I believe that maybe the tests are being run before the Toast elements are being created.

Here's the test result, as you can see the button is being added with the appropriate class:

enter image description here

CodePudding user response:

That's a very strange issue.

Could it be that the HTML element is not on the fixture.debugElement but on the document?

Try the following (query by nativeElement):

const retryButton = fixture.nativeElement.querySelector('.retry-button');
retryButton.click();

If the above doesn't work, try the following (query by document):

const retryButton = document.querySelector('.retry-button');
retryButton.click();

If none of the above works, then it could be that the element is getting painted asynchronously at a later point in time.

You can use this answer to help where you can do:

await waitUntil(() => !!document.querySelector('.retry-button'));

That should wait until .retry-button is in the DOM before continuing.

CodePudding user response:

The problem is the Toast button is actually a part of the shadow DOM. I was able to come to a working solution by accessing the correct shadow DOM:

it('should make a call to retrieval method on retry', async () => {
      spyOn(component, 'retrieveEntry');

      await component.retryRetrieval();
      fixture.detectChanges();

      const host = document.getElementById('retry-toast');
      const root = host.shadowRoot;
      const retryButton = root.querySelector('.retry-button') as HTMLElement;

      retryButton.click();
      fixture.detectChanges();

      expect(component.retrieveEntry).toHaveBeenCalled();
    });

I also set the id in htmlAttributes property in the ToastController to ensure consistency:

const toast = await this.toastController.create({
      message: 'An error occurred retrieving entry.',
      htmlAttributes: {
        id: 'retry-toast'
      },
      color: 'danger',
  • Related