Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Angular Material table is rendering correct data

I am using an Angular Material table to display a list of users, including email, created date and roles. My template looks like this:

<table mat-table [dataSource]="dataSource" multiTemplateDataRows matSort matSortActive="email" matSortDirection="asc">
  <ng-container matColumnDef="email">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Email</th>
    <td mat-cell *matCellDef="let user" class="user-email"><a [routerLink]="['/users', user.id]">{{user.email}}</a></td>
  </ng-container>

  <ng-container matColumnDef="created">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Created</th>
    <td mat-cell *matCellDef="let user">{{user.created | date: 'medium'}}</td>
  </ng-container>

  <ng-container matColumnDef="roles">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Roles</th>
    <td mat-cell *matCellDef="let user">{{user.roles.join(', ')}}</td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let user; columns: displayedColumns;"
      class="user-row">
  </tr>
</table>

I have unit tests to determine whether the data is loaded into the component, however I would also like to test whether the data has been rendered correctly in the template. To do this, I am trying to use the following test code:

it('should display the users email', () => {
  expect(component.users).toBe(testUsers);

  fixture.detectChanges();
  console.log(fixture.isStable()); // displays false
  fixture.whenRenderingDone().then(() => {
    console.log(fixture.isStable()); // displays true
    const emailElement = fixture.debugElement.query(By.css('.user-email'));
    console.log(emailElement);
  });
});

I would expect emailElement to be a list of each of the td elements with the class user-email, however it is always null.

Is there a way to test that the table contains the correct values?

like image 809
DeadPassive Avatar asked Jan 18 '19 09:01

DeadPassive


1 Answers

You are never actually assigning the class .user-email in your code example. You are only assigning the class .user-row to the element tr. If you want to get the elements by class, you could use the classes assigned by Angular Material. Each td element gets a class of the format mat-column-{columnName}, e.g. mat-column-email in your case.

Here is how I would test it:

it('should test the table ', (done) => {
  expect(component.users).toEqual(testUsers);

  fixture.detectChanges();
  fixture.whenStable().then(() => {
    fixture.detectChanges();

    let tableRows = fixture.nativeElement.querySelectorAll('tr');
    expect(tableRows.length).toBe(4);

    // Header row
    let headerRow = tableRows[0];
    expect(headerRow.cells[0].innerHTML).toBe('Email');
    expect(headerRow.cells[1].innerHTML).toBe('Created');
    expect(headerRow.cells[2].innerHTML).toBe('Roles');

    // Data rows
    let row1 = tableRows[1];
    expect(row1.cells[0].innerHTML).toBe('[email protected]');
    expect(row1.cells[1].innerHTML).toBe('01-01-2020');
    expect(row1.cells[2].innerHTML).toBe('admin,standard');

    // Test more rows here..

    done();
  });
});

You can find a working StackBlitz here.

like image 87
Fabian Küng Avatar answered Oct 25 '22 22:10

Fabian Küng