Jest: error Command failed with exit code 1

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

По сути в этой публикации речь пойдет о функции done() в jest. Функция очень полезная, так как позволяет разработчику решать в какой момент будет закончен тест. Бывают ситуации, когда это действительно очень нужно. В новом проекте я столкнулся с такой задачей и решил просто описать то, как я её решил.

В нашем проекте, при запуске unit тестов, командой

 yarn test:ci

, в конце выполнения появлялась ошибка error Command failed with exit code 1. Тесты были написаны на Jest в приложении на Angular 14.

Все тесты при этом были PASSED.

 error Command failed with exit code 1
error Command failed with exit code 1

В нашем случае под командой test:ci скрывалось следующее:

jest --ci --collectCoverage

Проверив оба параметра по отдельности, выяснилось, что источником ошибки является команда

yarn jest --ci.

Ошибка не совсем очевидная и выяснить причину было довольно сложно. В интернете есть ссылка, посвященная этой проблеме: https://github.com/facebook/jest/issues/9324. Точного объяснения причины этой ошибки, на момент написания этой публикации, там не было, но было сказано, что ошибка исчезает, если добавить --maxWorkers=2. При добавлении этого параметра ошибка исчезала и у нас. Параметр maxWorkers ограничивает максимально число рабочих потоков, о чем можно прочитать тут - https://jestjs.io/ru/docs/cli. Конечно, такой способ позволяет избежать ошибки, но реально он её не исправляет.

Чтобы найти причину ошибки были перегружены функции console.error и console.warn в файле jest.setup.js, в проекте он назывался setup-jest.ts. Проблема в том, что если в коде есть вызов команды console.error и мы пишем unit тест на этот код, то при выполнении мы увидим в логе сообщение об ошибке и стэк до этой ошибки. В случае с unit тестом, это ожидаемое поведение, так как мы пишем тест, в котором проверяем, как поведет себя приложение в случае ошибочных данных или состояний. Отсюда сам тест будет отмечен как PASSED, но в логе будет сообщение об ошибке, которую мы и хотели получить в тесте. Такие сообщения, да ещё и со stack trace, затрудняли поиск реальных ошибок. Чтобы отделить "хорошие" ошибки от "плохих" я написал в файле setup-jest.ts код представленный ниже:

// Write info message when a `console.error` or `console.warn` happens
// by overriding the functions
const CONSOLE_FAIL_TYPES = ['error', 'warn'];

CONSOLE_FAIL_TYPES.forEach((type) => {
  console[type] = (...params: string[]) => {
    console.info(`console.${type}\n class: ${params[0]}\n message: ${params[1]}`);
  };
});

Идея написать такую перегрузку функций была взята отсюда: https://www.benmvp.com/blog/catch-warnings-jest-tests/

После добавления такой перегрузки, при запуске тестов, на одном из них стала появляться такая ошибка: Cannot log after tests are done. Did you forget to wait for something async in your test?

Ошибка говорит о том, что тест был завершен раньше, чем отработали все асинхронные конструкции.

Код этого теста:

it('just a test', async () => {
  ...
  for (const incorrectJson of toFail) {
    ...
    await waitForExpect(() => {
      expect(component['funcWithPromiseHandler']).toHaveBeenCalled();
    }, 5000);
    expect(component['funcWitchCalledInHandler']).toHaveBeenCalled();
  }
  expect(someService.importSomth).toHaveBeenCalledTimes(0);
});

Было решено переписать этот код на Promise и использовать функцию jest done(), чтобы явно завершить этот тест тогда, когда это нам нужно. О том как она работает можно узнать тут: https://jestjs.io/docs/asynchronous, в разделе Callbacks.

Переписанный код:

it('just a test', (done: any) => {
  ...
  let promiseArr: Promise<{}>[] = []
  for (const incorrectJson of toFail) {
    ...
    promiseArr.push(waitForExpect(() => {
      expect(component['funcWithPromiseHandler']).toHaveBeenCalled();
    }, 5000).finally( () => {
      expect(component['funcWitchCalledInHandler']).toHaveBeenCalled();
    }));
  }
  Promise.all(promiseArr).then( () => {
    expect(someService.importSomth).toHaveBeenCalledTimes(0);
    done();
  }).catch ( (er) => {
    done(er);
  })
});

После этого команда:

 yarn test:ci

стала выполняться без ошибок:

Заключение

В публикации говориться не только о функции done(). Из примера видно, что среди множества тестов ошибка была только в одном. Выловить эту ошибку получилось благодаря перегрузке console.error и console.warn. Думаю, что показанный в этой публикации подход к решению данной проблемы будет полезен не только в данном конкретном случае, но и в решении других не менее сложных и запутанных ситуациях, которые могут возникнуть при работе с jest.

Источник: https://habr.com/ru/post/710342/


Интересные статьи

Интересные статьи

Сегодня с утра перестали работать сборки в jenkins, вылетали с ошибкой. Скрытый текст Terraform and earlier allowed provider version constraints insi...
The Dutch large-format FFF/FDM 3D printer manufacturer Builder has announced the Extreme 1500 HC — an upgraded version of the bestselling Extreme 1500 that features an active chamber heater allowing f...
Привет Хабр!Как вы все уже знаете, в области безопасности приложений без статических анализаторов исходного кода (SAST) совсем никуда. SAST-сканеры занимаются тем, что пр...
Бизнес-смыслы появились в Битриксе в начале 2016 года, но мало кто понимает, как их правильно использовать для удобной настройки интернет-магазинов.
С версии 12.0 в Bitrix Framework доступно создание резервных копий в автоматическом режиме. Задание параметров автоматического резервного копирования производится в Административной части на странице ...