Как выполнить модульное тестирование компонента после fromEvent FileReader.loadended - PullRequest
0 голосов
/ 10 января 2020

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

Учитывая следующий метод функционального компонента:

  submitFileForm(form: NgForm): void {
    if (this.uploadFile) {
      const reader = new FileReader();

      fromEvent(reader, 'error')
        .subscribe((e: ProgressEvent) => {
          console.error(e);
          reader.abort();
        });
      fromEvent(reader, 'loadend')
        .pipe(map(() => btoa(reader.result as string)))
        .subscribe(() => {
          // This works, but not in the test.
          component.step = 1;
        }, (err) => {
          console.error(err);
          this.step = -1;
        });

      reader.readAsText(this.uploadFile, 'UTF-8');
    }
 }

И следующий тест:

  it('should go from step 0 to step 1', () => {
    const mockBlob: any = new Blob([
      `A,B,C\naaaa,bbb,ccc`,
    ], { type: 'text/csv' });
    mockBlob.name = 'my.csv';
    const mockFile = mockBlob as File;
    component.uploadFile = mockFile;
    fixture.detectChanges();

    component.submitFileForm(component.fileForm);
    fixture.detectChanges();

    // This fails. component.step is 0. After the test is finished step is 1.
    expect(component.step).toEqual(1);
  }

Полный пример на https://stackblitz.com/edit/angular-zr3nej и https://angular-zr3nej.stackblitz.io/, который показывает дополнительную информацию. Они находятся в Angular 8.

Я пробовал

  • Абстрагирование читателя в свой собственный сервис.
  • Упаковка fromEvent с использованием NgZone.run и NgZone.runOutsideAngular.
  • Обтекание NgZone.run(() => { component.step = 1; });
  • Использование BehaviorSubject для шага формы.
  • Отметка ApplicationRef.
  • Использование fixture.whenStable() в тесте .

Но я думаю, что это, вероятно, связано с фундаментальным неправильным пониманием Angular или Zone и с тем, как правильно зарегистрировать отложенную задачу для компонента Angular. Также мог бы быть лучший способ структурировать код так, чтобы он был тестируемым модулем другим способом. Может быть, вместо ожидания отправки формы читатель всегда может читать? Или, может быть, async / await, но я не очень знаком с этими шаблонами в сочетании с Rx JS и Angular.

Я не пробовал вводить ChangeDetectionRef, потому что столкнулся с проблемой в прошлое с созданием , что тестируемым.

Шаблон ngSwitch здесь, вероятно, не самый чистый, но, по моему мнению, он все же должен быть возможен. Лично я, вероятно, разбил бы его на отдельные компоненты, но иногда нам нужно придерживаться общих стилей кода.

1 Ответ

1 голос
/ 10 января 2020

Абстрагирование в службу, похоже, работает сегодня. Возможно, у меня были и другие побочные эффекты, но мне больше нравится этот паттерн, и он выглядит чище в компоненте. Извините, если я потратил впустую время. Я не приму этот ответ, потому что, возможно, есть лучший ответ, объясняющий, с чем я столкнулся.

  export class FileReaderService {
      read(file: File): Observable<string> {
        return Observable.create((observer: Observer<string>) => {
          const reader = new FileReader();

          reader.onerror = () => {
            reader.abort();
            observer.error('An error occurred reading the file.');
          };

          reader.onloadend = () => {
            observer.next(reader.result as string);
            observer.complete();
          };

          reader.readAsText(file, 'UTF-8');
        });
      }
    }

изменение компонента:

  submitFileForm(form: NgForm): void {
    if (this.uploadFile) {
      this.fileReaderService.read(this.uploadFile)
        .subscribe(() => {
          component.step = 1;
        }, (err) => {
          console.error(err);
          this.step = -1;
        });
     }
   }

тестовое изменение:

  it('should go from step 0 to step 1', () => {
    const contents = `A,B,C\naaaa,bbb,ccc`;
    const reader = fixture.debugElement.injector.get(FileReaderService);
    spyOn(reader, 'read').and.returnValue(of(contents));

    const mockBlob: any = new Blob([contents]), { type: 'text/csv' });
    mockBlob.name = 'my.csv';
    const mockFile = mockBlob as File;
    component.uploadFile = mockFile;
    fixture.detectChanges();

    component.submitFileForm(component.fileForm);
    fixture.detectChanges();

    expect(component.step).toEqual(1);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...