angulartypescriptangular-materialjasmine

How do I test if a matTooltip is properly disabled in Angular Material?


I've got a loop creating several matCard elements. These represent events. Some of them are in the past. I give these a class to grey them out, and add a matTooltip to explain what that means.

<mat-card
  class="event-card"
  *ngFor="let event of events"
  [class.past-event]="event.alreadyHappened()"
  matTooltip="This event has already happened"
  [matTooltipDisabled]="event.alreadyHappened() === false"
>
  <mat-card-header>...</mat-card-header>
  <mat-card-content></mat-card-content>
</mat-card>

The alreadyHappened() method returns a boolean.

I would like to test that the disabled property is set correctly, but I can't find how to check that in the matTooltip documentation.

I've got two tooltip harnesses for two cards. I can confirm that they're attached to the right card.

it('should display tootltip on past events', async () => {
  const tooltips = await loader.getAllHarnesses(MatTooltipHarness);
  expect(tooltips.length).toBe(2);

  expect(
    await (await tooltips[0].host()).hasClass('past-event')
  ).toBeTrue();
  expect(
    await (await tooltips[1].host()).hasClass('past-event')
  ).toBeFalse();

  await tooltips[0].show();
  expect(await tooltips[0].getTooltipText()).toEqual(
    'This event has already happened'
  );
);

What I don't understand is how to get the disabled property. I found the tests for the actual matTooltip class, but I think I shouldn't be messing with internals.

I've figured out that I can get component instances for children with this answer.

const ttFixture = fixture.debugElement.queryAll(By.directive(MatTooltip));
console.log(ttFixture);

But this gives me two mat-card elements, not the tooltips.

Do I need to create a fixture for the tooltip, or is there something else I am missing?


Solution

  • Sometimes you just have to read the source. I ended up using what they do in the tests for matTooltip.

    We need to import By to get a predicate, and the MatTooltip.

    import { By } from '@angular/platform-browser'; 
    import { MatTooltipModule, MatTooltip } from '@angular/material/tooltip';
    

    We then need to import the MatTooltipModule into the TestBed. We also need animations to make the tooltip pop up.

    TestBed.configureTestingModule({
      declarations: [EventsComponent],
       //                       VVVVVVVVVVVVVVVV
       imports: [MatCardModule, MatTooltipModule, NoopAnimationsModule],
       ...
    

    And then we can use its injector to grab the component instances, which have properties.

        it('should display tootltip on past events', async () => {
          const ttDebugElements = fixture.debugElement.queryAll(By.css('.event-card'));
          const pastEventTooltip = ttDebugElements[0].injector.get<MatTooltip>(MatTooltip);
          const futureEventTooltip = ttDebugElements[1].injector.get<MatTooltip>(MatTooltip);
    
          expect(pastEventTooltip.disabled).toBeFalse();
          expect(futureEventTooltip.disabled).toBeTrue();
        });
    
    

    This works like a charm.