Модульный тестовый коврик-меню с Карма-Жасмин

У меня есть мат-меню, в котором содержание может отличаться в зависимости от пользователя. Я пытаюсь написать модульный тест, но, судя по тому, что я вижу, jasmine не видит CDK div, поэтому я не могу получить записи меню.

Мой шаблон:

<button id="account" mat-icon-button [matMenuTriggerFor]="menu" aria-label="Profile">
    <mat-icon>person</mat-icon>
</button>
<mat-menu #menu="matMenu">
    <button mat-menu-item *ngxPermissionsOnly="PERMISSION.USER_LIST" id="user-list" (click)="usersList()">
        <mat-icon>recent_actors</mat-icon>
    </button>
    <button mat-menu-item *ngxPermissionsOnly="PERMISSION.INFORMATIONS" id="informations" (click)="infoList()">
        <mat-icon>info</mat-icon>
    </button>
    <button mat-menu-item id="logout" (click)="logout()">
        <mat-icon>exit_to_app</mat-icon>
    </button>
</mat-menu>

Модульный тест:

let component: HeaderComponent;
let fixture: ComponentFixture < HeaderComponent > ;

const providers: any[] = headerProviders;

beforeEach(async (() => {
    TestBed.configureTestingModule({
            declarations: [
                HeaderComponent,
                NgxPermissionsRestrictStubDirective
            ],
            providers: providers,
            imports: [
                BrowserAnimationsModule,
                BrowserModule,
                CommonModule,
                CommonSogetrelModule,
                FlexLayoutModule,
                SharedMaterialModule,
                RouterTestingModule.withRoutes([])
            ]
        })
        .compileComponents()
        .then(() => {
            fixture = TestBed.createComponent(HeaderComponent);
            component = fixture.componentInstance;
        });
}));

it('should not display elements which needs permissions', () => {
    fixture.nativeElement.querySelector('#account').click();
    fixture.detectChanges();
    expect(logoutBtn).toBeTruthy('Le bouton Déconnexion doit être affiché');
    expect(fixture.debugElement.nativeElement.querySelector('#user-list')).toBeFalsy();

});

Я пробовал с

console.info(fixture.nativeElement.parentNode);
const menu = fixture.nativeElement.parentNode.querySelector('.mat-menu-panel');
expect(menu).toBeTruthy();

Что я вижу с console.info, так это то, что на странице нет CDK div, поэтому очевидно, что .mat-menu-panel не найден.

Есть идеи, как проверить содержимое мат-меню?


person Lempkin    schedule 28.04.2020    source источник
comment
Убедитесь, что в массиве imports есть MatMenuModule и MatIconModule. Скорее всего, он у вас есть, так как вы не получаете ошибок при компиляции.   -  person AliF50    schedule 28.04.2020
comment
Да, они есть в SharedMaterialModule   -  person Lempkin    schedule 28.04.2020
comment
пробовали ли вы fixture.debugElement.query(By.css('#account')).nativeElement.click() и expect(fixture.debugElement.query(By.css('#logout'))).toBeTruthy(), expect(fixture.debugElement.query(By.css('#user-list'))).toBeFalsy()?, тем не менее, я думаю, вам следует добавить любой вывод консоли или результат теста, фактически и то, и другое.   -  person Bargros    schedule 07.02.2021


Ответы (3)


Думаю, тебе стоит попробовать это с MatMenuHarness.

https://material.angular.io/components/menu/api#MatMenuHarness

it('should not display elements which needs permissions', async () => {
    let loader: HarnessLoader = TestbedHarnessEnvironment.loader(fixture);
    fixture.detectChanges();
    let menu = await testHarness.loader.getHarness(MatMenuHarness);
    let items = await menu.getItems();
    expect(items.length).toBe(1);
  });

person Den Ko    schedule 06.02.2021
comment
В моем случае menu.getItems() всегда возвращает ноль. Есть идеи, почему? Однако menu.isOpen() верно. - person itsji10dra; 14.06.2021

MatMenuHarness - правильный способ протестировать мат-меню, но в нем есть крошечная неинтуитивно понятная деталь. Данный:

<div class="view-contract__portal-header">
  <h2>Counterparties</h2>
  <button
    mat-stroked-button
    color="primary"
    data-testid="add-counterparty"
    [matMenuTriggerFor]="menu"
  >
    <mat-icon>add</mat-icon> Add counterparty
  </button>
</div>

<mat-menu #menu="matMenu" data-testid="add-counterparty-menu">
  <button
    *ngFor="let role of roles"
    mat-menu-item
    [attr.data-testid]="'add-counterparty-' + role"
    (click)="addCounterparty(role)"
  >
    {{ role }}
  </button>
</mat-menu>

Затем следует создать экземпляр MatMenuHarness, ища элемент, к которому применяется атрибут matMenuTriggerFor, а НЕ фактический элемент меню mat.

addCounterpartyMenu = await loader.getHarness<MatMenuHarness>(
  MatMenuHarness.with({
    selector: `[data-testid="add-counterparty"]`,
  }),
);

person Bat0u89    schedule 07.02.2021

Я думаю, проблема в том, что вы делаете все в одном и том же часовом взаимодействии, из-за этого DOM не будет обновляться до следующих часов.

Чтобы справиться с этим, вы можете использовать fakeAysnc и отметьте Angular.

Думаю, мы можем переписать ваш тест с помощью fakeAsync следующим образом:

    it('should not display elements which needs permissions', fakeAsync(() => {
        fixture.nativeElement.querySelector('#account').click();
        tick();
        fixture.detectChanges();
        expect(logoutBtn).toBeTruthy('Le bouton Déconnexion doit être affiché');
        expect(fixture.debugElement.nativeElement.querySelector('#user-list')).toBeFalsy();
      }));

Я думаю, это должно сработать.

person German Quinteros    schedule 29.04.2020