Как протестировать оператор forkJoin () с помощью jasmine-marbles

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

Вот мой сервисный код:

export class FormSubmitService {
  constructor(private http: HttpClient) {}

  public submit(data, attachments) {
    const observables = [
      ...attachments.map((file) => this.uploadAttachment(file)),
    ];

    return forkJoin(...observables)
      .pipe(
        defaultIfEmpty([]),
        map((tokens) => {
          return tokens.map((tokenObj) => tokenObj.attachment_token);
        }),
        switchMap((tokens: string[]) => {
          const formData = {
            data,
            attachments: tokens,
          };

          return this.submitForm(formData);
        }),
      );
  }

  private uploadAttachment(attachment: File) {
    const attachmentData: FormData = new FormData();
    attachmentData.append('attachment', attachment, attachment.name);

    return this.http.post(
      '/some/form/endpoint/attachments',
      attachmentData,
    );
  }

  private submitForm(userData: UserData) {
    return this.http.post(
      `/some/form/endpoint/form`,
      userData,
    );
  }
}

Если пользователь добавляет одно или несколько вложений, то, прежде чем я отправлю данные пользователя в серверную часть, мне нужно загрузить каждое вложение в серверную часть, чтобы получить токен каждого вложения, который позже я сохраню в массиве. Я делаю это с помощью forkJoin(), ожидая загрузки всех вложений, а затем использую switchMap для отправки пользовательских данных.

Вот два моих тестовых примера (один рабочий, другой неработающий):

describe('SubmitFormData', () => {
  let service: FormSubmitService;
  let http: jasmine.SpyObj<HttpClient>;

  beforeEach(() => {
    http = jasmine.createSpyObj('HttpClient', ['post']);
    service = new FormSubmitService(http);
  });

  describe('#submit', () => {
    const file = new File([''], 'filename', { type: 'image/png' });
    const attachments = [file];
    const data = {
      name: 'name',
      description: 'description',
    };

    // NOT WORKING!
    it('submit with attachment', () => {
      const expected = cold('-a--b-', { a: ['token'], b: { id: 'id_123' } }); // FAIL!
      // const expected = cold('----'); // SUCCESS!
      http.post.and.returnValues(
        cold('-a-', { a: [{ attachment_token: 'token' }] }),
        cold('-a-', { a: { id: 'id_123' } }),
      );

      const output = service.submit(data, attachments);

      expect(output).toBeObservable(expected);
      expect(http.post).toHaveBeenCalled();
    });

    // WORKING!
    it('submit without attachment', () => {
      const response = {
        id: 'id_123',
      };
      const expected = cold('-a-', { a: response });
      http.post.and.returnValues(
        cold('-a-', { a: { id: 'id_123' } }),
      );

      const output = service.submit(data, []);

      expect(output).toBeObservable(expected);
      expect(http.post).toHaveBeenCalled();
    });
  });
});

Проверить, где данные формы находятся без вложений, успешно, но проверить, где данные формы с вложениями, не удалось.

Сообщение об ошибке из-за сбоя:

✖ отправить с вложением HeadlessChrome 71.0.3578 (Mac OS X 10.14.2) Ошибка: ожидаемое значение $ .length = 0 равно 2. Ожидаемое значение $ [0] = undefined равно объекту ({frame: 10, notification: Notification ({kind : 'N', значение: ['токен'], ошибка: не определено, hasValue: true})}). Ожидается, что $ [1] = undefined равно Object ({frame: 40, notification: Notification ({kind: 'N', value: Object ({id: 'id_123'}), error: undefined, hasValue: true})} ).

Похоже, что output не излучает наблюдаемую в неудачном тесте, а undefined, но вопрос в том, почему? Потому что в другом тесте он выдает его, когда не отправляет вложение и использует forkJoin().

Кто-нибудь знает, почему это могло быть так? Спасибо!


person Toms Tumshais    schedule 24.01.2019    source источник


Ответы (1)


Исправлена ​​эта проблема, проблема заключалась в первом наблюдаемом, который был возвращен из http.post вызова - cold('-a-', { a: [{ attachment_token: 'token' }] }),. Он не испускал новую наблюдаемую, и на этом все испытания остановились. Изменил его на of({ attachment_token: 'token' }),, и тест прошел успешно.

Вот код:

it('submit with attachment', () => {
  const response = {
    id: 'id_123',
  };
  http.post.and.returnValues(
    of({ attachment_token: 'token' }),
    cold('-a', { a: response }),
  );
  const expected = cold('-a', { a: response });

  const output = service.submit(data, attachments);

  expect(output).toBeObservable(expected);
  expect(http.post).toHaveBeenCalledTimes(2);
})
person Toms Tumshais    schedule 25.01.2019