Как проверить статус обещания внутри Promise.finally (), не дожидаясь его в производственном коде - PullRequest
1 голос
/ 06 августа 2020

Я использую Promise.prototype.finally () (или try-catch-finally в функции async) в своем производственном коде для выполнения некоторого последующего кода без изменения статуса разрешения / отклонения текущего обещания.

Однако в моих тестах Jest я хотел бы обнаружить, что Promise внутри блока finally не был отклонен .

edit : Но я не хочу на самом деле ждать Promise в моем «производственном» коде (там меня волнуют только ошибки, повторно выданные из catch, но не ошибки из finally).

Как можно Я проверяю это? Или, по крайней мере, как имитировать Promise.prototype, чтобы отклонить текущее обещание об исключениях из finally?

Например, если бы я тестировал создателей действий redux, тесты проходят, даже если есть сообщение о необработанном Отклонение обещания:

https://codesandbox.io/s/reverent-dijkstra-nbcno?file= / src / index.test. js

test("finally", async () => {
  const actions = await dispatchMock(add("forgottenParent", { a: 1 }));
  const newState = actions.reduce(reducer, undefined);
  expect(newState).toEqual({});
});

const dispatchMock = async thunk => {...};

// ----- simplified "production" code -----

const reducer = (state = {}, action) => state;
const add = parentId => async dispatch => {
  dispatch("add start");
  try {
    await someFetch("someData");
    dispatch("add success");
  } catch (e) {
    dispatch("add failed");
    throw e;
  } finally {
    dispatch(get(parentId)); // tests pass if the promise here is rejected
  }
};
const get = id => async dispatch => {
  dispatch("get start");
  try {
    await someFetch(id);
    dispatch("get success");
  } catch (e) {
    dispatch("get failed");
    throw e;
  }
};
const someFetch = async id => {
  if (id === "forgottenParent") {
    throw new Error("imagine I forgot to mock this request");
  }
  Promise.resolve(id);
};

Ответы [ 2 ]

1 голос
/ 06 августа 2020
dispatch(get(parentId)); // tests pass if an exception is thrown here

В этой строке нет исключения. get(parentId) может вернуть отклоненное обещание (или ожидающее обещание, которое будет отклонено позже), но это не исключение и не повлияет на поток управления.

Возможно, вы ищете

const add = parentId => async dispatch => {
  dispatch("add start");
  try {
    await someFetch("someData");
    dispatch("add success");
  } catch (e) {
    dispatch("add failed");
    throw e;
  } finally {
    await dispatch(get(parentId));
//  ^^^^^
  }
};

Обратите внимание, что генерирование исключений из блока finally не совсем лучшая практика , хотя.

0 голосов
/ 06 августа 2020

edit : более общие решения доступны на { ссылка }


Можно сохранить Promise в переменной, доступной в некоторой вспомогательной функции, которая используется только для тестов, например:

export const _getPromiseFromFinallyInTests = () => _promiseFromFinally
let _promiseFromFinally

const add = parentId => async dispatch => {
  ...
  } finally {
    // not awaited here because I don't want to change the current Promise
    _promiseFromFinally = dispatch(get(parentId));
  }
};

и обновите тест, чтобы дождаться только тестового обещания:

test("finally", async () => {
  ...
  // but I want to fail the test if the Promise from finally is rejected
  await _getPromiseFromFinallyInTests()
});
...