AngularCli - подписка не выполняется внутри onSubmit во время теста - PullRequest
0 голосов
/ 24 апреля 2018

Я пытаюсь протестировать компонент, который в основном имеет поле для электронной почты и пароля.Как только эти два поля заполнены, пользователь может нажать на кнопку и отправить запрос на сервер.Когда я тестирую этот компонент через браузер, он выполняет поведение, которое я хочу.Но когда я использую файл спецификации для тестирования компонента, метод subscribe никогда не выполняется (obs: я издеваюсь над сервисом).Вот метод onSubmit для компонента:

onSubmit(formAuthentication: NgForm) {
  if (this.credential.email == undefined || this.credential.password == undefined) {
    this.error = "Preencha o campo de email e de senha para continuar"
    return;
  } else {
    this.tokenManagerService.generateNewToken(this.credential);
    this.tokenManagerService.retrieveToken().subscribe(token => {
      console.log(token);
      const tokenRetrieved = JSON.parse(token);
      if (tokenRetrieved.error) {
        this.error = tokenRetrieved.error;
      } else {
        foo();
      }
    });
    formAuthentication.resetForm();
  }
}

Это конфигурация для файла спецификации и самого теста:

describe('AuthenticationComponent', () => {
  let component: AuthenticationComponent;
  let fixture: ComponentFixture<AuthenticationComponent>;
  let inputEmail: HTMLInputElement;
  let inputPassword: HTMLInputElement;
  let loginButton: HTMLInputElement;
  let tokenManagerServiceMock: TokenManagerServiceMock;
  let mockRouter = {
    navigate: jasmine.createSpy('navigate')
  }
  beforeEach(() => {
    tokenManagerServiceMock = new TokenManagerServiceMock();
    TestBed.configureTestingModule({
      declarations: [ AuthenticationComponent ],
      imports: [ FormsModule, HttpModule,RouterTestingModule.withRoutes([]) ],
      providers: [
        { provide: TokenManagerService, useValue: tokenManagerServiceMock }
      ]
    });
    TestBed.overrideComponent(AuthenticationComponent, {
      set: {
        providers: [
          { provide: TokenManagerService, useValue: tokenManagerServiceMock }
        ]
      }
    });

    fixture = TestBed.createComponent(AuthenticationComponent)
    fixture.componentInstance.ngOnInit();
    tokenManagerServiceMock = TestBed.get(TokenManagerService);
    fixture.detectChanges();
    inputEmail = fixture.debugElement.nativeElement.querySelector('input[type=text]');
    inputPassword = fixture.debugElement.nativeElement.querySelector('input[type=password]');
    loginButton = fixture.nativeElement.querySelector('input[type=submit]');
  });

  it('should detect white field message',() => {
    fixture.whenStable().then(() => {
      inputEmail.value = faker.internet.email();
      inputEmail.dispatchEvent(new Event('input'));
      inputPassword.value = faker.internet.password();
      inputPassword.dispatchEvent(new Event('input'));
      loginButton.click();
      fixture.detectChanges();
    });
  });
});

Что я мог сделать неправильно?

РЕДАКТИРОВАНИЕ 1 : Я почти уверен, что метод subscribe никогда не выполняется, потому что внутри метода подписки, если есть узел с именем token.error, компонент должен установитьпеременная ошибки, которая будет отображаться в этом блоке:

<div class="error-block" *ngIf="error">
  <h6>{{ error }}</h6>
</div>

Но это сообщение никогда не появляется в Карме.

EDIT 2 : Это мой mockService для имитации оригиналаслужба аутентификации:

import { Injectable }  from '@angular/core';
import { Credential } from '../models/credential';
import { AuthenticationService } from './authentication.service'
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import * as token from 'rand-token';

@Injectable()
export class TokenManagerServiceMock {

  private tokenKey: string = 'codeToken';
  private subject = new Subject<any>();

  constructor() {}

  public generateNewToken(credential: Credential): void {
    let currentTime:number = (new Date()).getTime();
    if (credential.email == 'eminetto@coderockr.com') {
      const data = token.suid(24);
      this.subject.next(JSON.stringify({ttl: currentTime, data}));
    } else {
      const error = 'Usuário ou senha inválidos';
      this.subject.next(JSON.stringify({ttl: currentTime, error}));
    }
  }

  public retrieveToken(): Observable<string> {
    console.log('achieved retrieve');
    return this.subject.asObservable();
  }
}

1 Ответ

0 голосов
/ 25 апреля 2018

Основная причина проблемы в вашем тесте заключается в том, что тема вашего смоделированного класса была настроена с использованием класса rxjs Subject.Использование, которое у вас есть, указывает на то, что вы на самом деле должны использовать класс BehaviorSubject, чтобы любые поздние подписчики на тему (подписавшиеся после того, как значение помещено в тему) могут получить самое последнее значение при подписке.

Зная о том, что происходит в фиктивной службе, мы можем видеть, что у нас есть поздний подписчик:

generateNewToken(credential: Credential): void {
  ...
  this.subject.next(...);
  ...
}

retrieveToken(): Observable<string> {
  return this.subject.asObservable();
}

Вы можете увидеть это поведение при использовании макета ниже:

this.tokenManagerService.generateNewToken(this.credential);
this.tokenManagerService.retrieveToken().subscribe(...);

Сначала мы генерируем новый токен и помещаем его в тему, возвращаемся обратно к компоненту и, наконец, подписываемся на тему.При переключении на BehaviorSubject у нас не возникнет проблем с тем, что последний подписчик не увидит значение, выдвинутое из вызова для генерации нового токена.

...