Я хотел бы объяснить, почему это вообще не сработало.
Как вы знаете, когда вы тестируете наблюдаемые с помощью мраморных диаграмм, вы не используете реальные время , но виртуальное время . Виртуальное время можно измерить в frames
. Значение кадра может варьироваться (например, 10
, 1
), но независимо от значения это то, что помогает проиллюстрировать ситуацию, с которой вы имеете дело.
Например, с hot(--a---b-c)
, вы описываете наблюдаемое, которое будет выдавать следующие значения: a
в 2u
, b
в 6u
и c
в 8u
(u
- единицы времени).
Внутренне, Rx Js создает очередь действий , и задача каждого действия состоит в том, чтобы выдать значение, которое ему было присвоено. {n}u
описывает, когда действие выполнит свою задачу.
Для hot(--a---b-c)
очередь действий будет выглядеть примерно так:
queue = [
{ frame: '2u', value: 'a' }/* aAction */,
{ frame: '6u', value: 'b' }/* bAction */,
{ frame: '8u', value: 'c' }/* cAction */
]
* При вызове 1033 * и cold
будут созданы экземпляры наблюдаемых hot
и cold
соответственно. Их базовый класс расширяет класс Observable
.
Теперь очень интересно посмотреть, что происходит, когда вы имеете дело с внутренними наблюдаемыми, как показано в вашем примере:
actions$ = hot('-a', { a: action}); // 'a' - emitted at frame 1
const response = cold('-#|', {}, errorMessage); // Error emitted at 1u after it has been subscribed
productServiceMock.getProducts = jest.fn(() => response);
const expected = cold('--(b|)', { b: outcome }); // `b` and `complete` notification, both at frame 2
response
observable подписан из-за a
, что означает, что уведомление об ошибке будет отправлено по адресу frame of a
+ original frame
. То есть frame 1
(прибытие a
) + frame1
(при возникновении ошибки) = frame 2
.
Итак, почему hot('-a')
не сработало?
Это из-за того, как mergeMap
обрабатывает вещи. При использовании mergeMap
и его братьев и сестер, если источник завершается, но оператор имеет внутренние наблюдаемые, которые все еще активны ( еще не завершено ), полное уведомление источника не будет передано. Это произойдет только тогда, когда все внутренние наблюдаемые также будут завершены.
С другой стороны, если все внутренние наблюдаемые объекты завершены, но источник не завершил работу, полное уведомление не будет передано следующему подписчик в сети. Вот почему он изначально не работал .
Теперь давайте посмотрим, почему это работает так:
actions$ = hot('-a|', { a: action});
const response = cold('-#|)', {}, errorMessage);
productServiceMock.getProducts = jest.fn(() => response);
const expected = cold('--(b|)', { b: outcome });
очередь действий теперь будет выглядеть так:
queue = [
{ frame: '1u', value: 'a' },
{ frame: '2u', completeNotif: true },
]
При получении a
будет подписана response
, и поскольку это наблюдаемое, созданное с помощью cold()
, его уведомления будут должны быть назначены действиям и помещены в очередь соответственно.
После того, как response
был подписан, очередь будет выглядеть следующим образом:
queue = [
// `{ frame: '1u', value: 'a' },` is missing because when an action's task is done
// the action itself is removed from the queue
{ frame: '2u', completeNotif: true }, // Still here because the first action didn't finish
{ frame: '2u', errorNotif: true, name: 'Load products fail' }, // ' from '-#|'
{ frame: '3u', completeNotif: true },// `|` from '-#|'
]
Обратите внимание, что если 2 действия очереди должен передаваться в том же кадре, приоритет будет иметь самый старый.
Из вышеизложенного мы можем сказать, что источник будет выдавать полное уведомление до внутренний наблюдаемый объект выдаст ошибку, это означает, что когда внутренний наблюдаемый будет выдавать значение, полученное в результате обнаружения ошибки (outcome
), mergeMap
будет передавать полное уведомление.
Наконец, (b|)
необходим в cold('--(b|)', { b: outcome });
, потому что наблюдаемое catchError
su bscribes to, of(new productActions.LoadFail(error)))
, будет сгенерирован и завершен в том же кадре. Текущий кадр содержит значение кадра текущего выбранного действия. В данном случае это 2
, из { frame: '2u', errorNotif: true, name: 'Load products fail' }
.