угловое модульное тестирование асинхронных и синхронных задач - PullRequest
0 голосов
/ 23 ноября 2018

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

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { LoginComponent } from './login.component';
import {BrowserModule, By} from '@angular/platform-browser';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {Component, DebugElement, Input} from '@angular/core';
import {RouterTestingModule} from '@angular/router/testing';
import {LoaderService} from '@shared/services/loader.service';
import {AuthenticationService} from '@shared/services/authentication.service';
import {HttpClientModule} from '@angular/common/http';
import {CommonService} from '@shared/services/common.service';
import {ExploreService} from '@shared/services/explore.service';
import {TitleService} from '@shared/services/title.service';
import {AppConfig} from '../../app-config.service';
import {ThemeService} from '@shared/services/theme.service';
import {MatDialog, MatFormFieldModule, MatIconModule} from '@angular/material';
import {throwError} from 'rxjs';

@Component({
  selector: 'show-errors',
  template: '<p>Mock Product Settings Component</p>'
})
class MockShowErrorsComponent {
  @Input() public control;
}
describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let authService: any;
  let common: any;
  let explore: any;
  let title: any;
  let config: any;
  let theme: any;
  let dialog: any;
  let debugElement: DebugElement;
  let element: HTMLElement;
  let submitSpy: any;
  beforeEach(async(() => {
    authService = jasmine.createSpyObj('AuthenticationService', [
      'login',
      'logout'
    ]);
    common = jasmine.createSpyObj('commonService', [
      'updateCurrentUrl',
      'isMobile',
    ]);
    explore = jasmine.createSpyObj('exploreService', [
      'slowCalcMessage',
      'cancelSlowMessage',
      'getInventoryTotalSummary',
      'handleError',
      'getMarketData'
    ]);
    title = jasmine.createSpyObj('titleService', [
      'getTitle',
      'setTitle',
      'updateTitle',
      'updateSiteName'
    ]);
    config = jasmine.createSpyObj('AppConfigService', [
      'load',
      'API_ENDPOINT'
    ]);
    theme = jasmine.createSpyObj('ThemeService', [
      'getThemeSettings',
      'generateColorTheme',
    ]);
    dialog = jasmine.createSpyObj('dialog', [
      'open'
      ]);
    TestBed.configureTestingModule({
      imports: [
        BrowserModule,
        FormsModule,
        ReactiveFormsModule,
        RouterTestingModule.withRoutes([]),
        HttpClientModule,
        MatIconModule,
        MatFormFieldModule,
      ],
      declarations: [
        LoginComponent,
      MockShowErrorsComponent
      ],
      providers: [
        LoaderService,
        {provide: AuthenticationService, useValue: authService},
        {provide: CommonService, useValue: common},
        {provide: ExploreService, useValue: explore},
        {provide: TitleService, useValue: title},
        {provide: AppConfig, useValue: config},
        {provide: ThemeService, useValue: theme},
        {provide: MatDialog, useValue: dialog},
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
    debugElement = fixture.debugElement;
    element = debugElement.nativeElement;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
  it('should fail on wrong credentials', () => {
    const email = element.querySelector('#defaultForm-email') as HTMLInputElement;
    email.value = 'vigneshm@intermx.com';
    email.dispatchEvent(new Event('input'));
    const password = element.querySelector('#defaultForm-pass') as HTMLInputElement;
    password.value = 'agira123';
    password.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    const service = debugElement.injector.get(AuthenticationService);
    submitSpy = spyOn(service, 'logout');
    debugElement.query(By.css('button.login-btn'))
      .triggerEventHandler('click', null);
    fixture.detectChanges();
    expect(submitSpy).toHaveBeenCalled();
  });
});

Приведенный выше код - это мои спецификации и макеты для экрана входа в систему. Я понял, что на странице входа в систему слишком много зависимостей, которые необходимо упростить, когда они начинают имитировать их.

Реальная проблема заключается в том, что всякий раз, когда я запускаю это, второй тест завершается неудачно с TypeError: Cannot set property 'value' of null.

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

Ответы [ 4 ]

0 голосов
/ 26 ноября 2018

Я исправил ошибку, проблема была с шаблоном.У меня был глобальный оператор * ngIf, проверяющий наличие переменной, называемой настройками темы

<div *ngIf="themeSettings"></div>

, и в тестах я забыл заглушить переменную themeSettings, что привело к DOMтребуется для теста, который никогда не будет создан.После того как я добавил значение заглушки для themeSettings, оно снова заработало.

Вывод: если в вашем шаблоне есть ngIf, обязательно заглушите его и задайте правильные значения для этих значений в своих тестах и ​​убедитесь, чтоDOM создан правильно перед проверкой.

0 голосов
/ 23 ноября 2018

Думаю, что ваша проблема const email = element.querySelector('#defaultForm-email') as HTMLInputElement; и все такое element.querySelector

Обычно вы должны использовать fixture.nativeElement.querySelector(className); или id.Поскольку ваш TestBed обычно создает вам безопасную среду для выполнения тестов.

Обычно вы должны использовать что-то вроде строки,

const password: HTMLInputElement = fixture.nativeElement.querySelector('#defaultForm-pass');
 password.setValue('value');
0 голосов
/ 24 ноября 2018

Я смоделировал ваш тест в Stackblitz .Как вы можете видеть в Stackblitz, тесты теперь оба проходят.Вот что я сделал, чтобы заставить его работать:

  • Прежде всего я должен был догадаться о вашем компоненте, так как вы не включили эти детали.Не стесняйтесь раскошелиться на то, что я сделал, и замените его реальными деталями вашего компонента, чтобы посмотреть, сможете ли вы воспроизвести вашу ошибку.
  • Мне пришлось импортировать оба MatInputModule и BrowserAnimationsModule для TestBed для правильного создания.
  • Я прокомментировал строку submitSpy = spyOn(service, 'logout'), так как вы уже прошли шпиона, нет необходимости снова шпионить.Поэтому я также изменил последнюю строку на expect(service.login).toHaveBeenCalled();, чтобы проверить шпиона, который уже был передан.
  • Я добавил async () вокруг второй beforeEach, где вы фактически создаете компонент TestBed.
  • Я добавил fixture.whenStable(), чтобы убедиться, что все было правильно отрисовано перед тестированием.

Надеюсь, это поможет.

0 голосов
/ 23 ноября 2018

используйте vsc и установите тестовый плагин simon.Теперь щелкните правой кнопкой мыши на компоненте, для которого вы хотите написать модульные тесты.выберите опцию генерировать тесты.он сгенерирует файл спецификации со всеми зависимостями, записанными там.Теперь скопируйте и вставьте контрольные примеры вашего файла выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...