Jest: Jest не выходил через одну секунду после завершения тестового запуска.

Созданный на 26 окт. 2018  ·  33Комментарии  ·  Источник: facebook/jest

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

🐛 Отчет об ошибке

Jest не выходил через одну секунду после завершения тестового запуска.

Обычно это означает, что есть асинхронные операции, которые не были остановлены в ваших тестах. Для устранения этой проблемы рассмотрите возможность запуска Jest с --detectOpenHandles .

Воспроизводить

У меня есть функция, которая должна сделать запрос к внешнему API, и в том же методе просто сохранить в базе данных, не дожидаясь ответа.

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

Ожидаемое поведение

Исключенная шутка остановиться и вернуться к консоли.

Ссылка на ответ или репо (настоятельно рекомендуется)

line49 и line50

test("it should create new order", async () => {
  const response = await server.inject({
    method: "POST",
    url: "/api/orders",
    payload: JSON.stringify({
      customer: {
        email: "[email protected]",
        phone: "20 51 75 95",
        city: "Aarhus",
        zip: "8000",
        first_name: "jamal",
        last_name: "soueidan"
      },
      properties: [
        {
          name: "custom engraving",
          value: "Happy Birthday Mom!"
        }
      ]
    })
  });

  expect(response.statusCode).toBe(200);
});

Мне пришлось внести эти изменения, чтобы шутка работала с моим сервером api и mongodb.
https://github.com/jamalsoueidan/giv-et-tilbud/commit/d8f326b6294f88d1f12136042d4adfdc83328201

Запустить npx envinfo --preset jest

  System:
    OS: Windows 10
    CPU: x64 Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
  Binaries:
    npm: 6.4.1 - C:\Program Files\nodejs\npm.CMD

Самый полезный комментарий

Я получал ту же ошибку в одном из моих интеграционных тестов. В нем я использовал Sequelize Model для установки базы данных в известное состояние в beforeAll или beforeEach . Исправление заключалось в вызове close экземпляра Sequelize, подключенного к модели, в обратном вызове afterAll . Надеюсь, это поможет кому-то другому.

ИЗМЕНИТЬ:

И по многочисленным просьбам вот что я фактически сделал:

# dbConnection.js
export default new Sequelize({...}); // The Sequelize instance.
# some.spec.js
import dbConnection from './dbConnection';

const { SomeModel } = dbConnection.models;

describe('...', () => {
  beforeEach(async () => {
      await SomeModel.create({...});
  });
  ...
});

afterAll(async done => {
  // Closing the DB connection allows Jest to exit successfully.
  dbConnection.close();
  done();
});

@ Shrikant9
@AnitaMartinez

Я добавил пример.

Все 33 Комментарий

Попробуйте поместить "готово" в обратный вызов из тестовой функции следующим образом:

const whateverYouExpect = 123;
test('some description of test', async (done) => {  
    await someAsyncTask();  
    await secondAsyncTask();  
    evenCallbacksCanWork((result) => {  
        expect(result).toBe(whateverYouExpect);  
        done();
    });  
})

Кроме того, если соединение остается открытым, это также остановит выполнение теста, поэтому также рекомендуется закрыть любое открытое соединение.

Спасибо ExoMemphiz, но этот обратный вызов, откуда я должен связаться с ним?

Это слишком глубоко внутри сервера.

Перешел на Аву, из коробки работает 👍

Ну что ж, брат мой датчанин :)

Проблема в том, что я использую mongoose, чтобы сохранить что-то асинхронно, когда я вызываю этот api, и я не могу добраться до этого кода, чтобы выяснить, когда он завершил сохранение документа внутри mongo.

await server.inject

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

Я пытался отключить мангуста и закрыть каждое соединение, но это не сработало.

Я получал ту же ошибку в одном из моих интеграционных тестов. В нем я использовал Sequelize Model для установки базы данных в известное состояние в beforeAll или beforeEach . Исправление заключалось в вызове close экземпляра Sequelize, подключенного к модели, в обратном вызове afterAll . Надеюсь, это поможет кому-то другому.

ИЗМЕНИТЬ:

И по многочисленным просьбам вот что я фактически сделал:

# dbConnection.js
export default new Sequelize({...}); // The Sequelize instance.
# some.spec.js
import dbConnection from './dbConnection';

const { SomeModel } = dbConnection.models;

describe('...', () => {
  beforeEach(async () => {
      await SomeModel.create({...});
  });
  ...
});

afterAll(async done => {
  // Closing the DB connection allows Jest to exit successfully.
  dbConnection.close();
  done();
});

@ Shrikant9
@AnitaMartinez

Я добавил пример.

Я получал ту же ошибку в одном из моих интеграционных тестов. В нем я использовал Sequelize Model для установки базы данных в известное состояние в beforeAll . Исправление заключалось в вызове close в экземпляре Sequelize, подключенном к модели, в обратном вызове afterAll . Надеюсь, это поможет кому-то другому.

Какую версию Sequelize вы используете? Я получаю sequelizeInstance.close() не функция.

Я получал ту же ошибку в одном из моих интеграционных тестов. В нем я использовал Sequelize Model для установки базы данных в известное состояние в beforeAll . Исправление заключалось в вызове close в экземпляре Sequelize, подключенном к модели, в обратном вызове afterAll . Надеюсь, это поможет кому-то другому.

Вы можете показать свой код?

Привет, я получал ту же ошибку, с подсказкой @dhurlburtusa , мой код был @AnitaMartinez , я новичок в TypeScript, поэтому я почти уверен, что это можно сделать лучше:

let conn: Connection;
const createGlobalDatabaseConnection = (fn: Function) => dbConnection().then((conn: Connection) => fn(conn));

createGlobalDatabaseConnection((connection: Connection) => {
    conn = connection;
});

const closeGlobalDatabaseConnection = async () => {
    await conn.close();
}

afterAll(async () => {
    await closeGlobalDatabaseConnection();
});

dbConnection Promise - это функция, которая фактически подключается к экземпляру базы данных.

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

const mongoose = require('mongoose')
describe(' ...... ', ()=>{
  afterAll( async () =>{
        await mongoose.connection.close()
    })
})

Была эта проблема с тестами, которые использовали firebase. Это исправлено:

beforeAll(async () => {
  await firebase.firestore().enableNetwork();
});

afterAll(async () => {
  await firebase.firestore().disableNetwork();
});

Если у вас несколько тестовых файлов, я использую глобальную настройку и разборку. Например, в jest.config.js я определил:

module.exports = {
    globalSetup: './setupTests.js',
    globalTeardown: './teardownTests.js',
};

В setupTests я подключаюсь к базе данных и возвращаю функцию, которая возвращает обещание. Точно так же в teardownTests я закрываю соединение с базой данных и возвращаю функцию, которая возвращает обещание.

У меня была эта проблема с Knex и с использованием глобальных файлов настройки и удаления на Jest.

Мое решение было:

// setup.js
const knexConfiguration = require('../config/knex')[process.env.NODE_ENV];
const knex = require('knex');

const setup = async () => {
  const client = knex(knexConfiguration)
  await client.migrate.latest();
  await client.destroy();
};

module.exports = setup;
// teardown.js
const knexConfiguration = require('../config/knex')[process.env.NODE_ENV];
const knex = require('knex');

const teardown = async () => {
  const client = knex(knexConfiguration)
  await client.migrate.rollback();
  await client.destroy();
};

module.exports = teardown;

Надеюсь, это поможет любому, кто сталкивается с такой проблемой.

Всем привет,

Пожалуйста, поправьте меня, если я ошибаюсь, но это похоже на проблему, которая не на стороне Jest.

Если вы хотите, чтобы тесты завершались даже при наличии внешних ресурсов, я думаю, вам следует использовать --forceExit . Флаг forceExit специально разработан для этого случая и, следовательно, указывает на то, что невыполнение тестов, когда его нет, действительно является ожидаемым поведением, а не ошибкой.

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

Как упомянул автор, для отладки этого можно использовать --detectOpenHandles (и это также упоминается в документации, кстати).

Учитывая приведенные выше аргументы, возможно, этот вопрос можно было бы закрыть?

@lucasfcosta Каждый раз, когда я пытался использовать --detectOpenHandles в своем тестовом коде в нескольких разных приложениях на протяжении многих лет, он никогда не давал мне никаких полезных результатов. Он просто сидит и ждет, пока все завершится, но не выводит предупреждение, предлагающее в первую очередь использовать аргумент. Есть ли какой-нибудь трюк для получения полезного вывода из этого аргумента, о котором я не знаю?

Есть ли другой способ отладки? --detectOpenHandles не показывает никаких результатов. Спасибо

То же самое. Я не получаю вывода из --detectOpenHandles .

$ yarn test:types && jest --config ../../jest.config.js --detectOpenHandles
$ tsc --noEmit
 PASS  src/App.test.tsx (9.447s)
  √ renders without crashing (240ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.201s, estimated 14s
Ran all test suites.
(node:9784) UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1126:14)
(node:9784) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a prom
ise which was not handled with .catch(). (rejection id: 2)
(node:9784) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-z
ero exit code.

Мой jest.config.js :

module.exports = {
  bail: true,
  collectCoverage: false,
  collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/index.tsx', '!src/main.ts', '!**/node_modules/**'],
  coverageDirectory: '<rootDir>/coverage',
  coverageThreshold: {
    global: {
      branches: 100,
      functions: 100,
      lines: 100,
      statements: 100,
    },
  },
  moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx'],
  rootDir: process.cwd(),
  testMatch: ['<rootDir>/src/**/*.test.{ts,tsx}'],
  transform: {
    '^.+\\.tsx?$': 'ts-jest',
  },
  verbose: true,
};

Мой тестовый пример:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
  ReactDOM.unmountComponentAtNode(div);
});

Для тех, кто сталкивался с этим с помощью sequelize , мне пришлось сделать следующее:

  afterAll(async done => {
    await models.sequelize.close();
    done();
  });

Это устранило проблему.

Я тестирую Jest с помощью мангуста и супертеста, добавил testEnvironment: 'node' исправил эту проблему для меня.

Еще одна возможная причина, с которой я столкнулся - не закрытое соединение Redis.

afterAll(async done => {
   globalRedisClient.unref();
   done();
});

Мое решение не сработает для всех, но если вы рыскали по сети, пока я пытался выяснить, как закрыть этот проклятый дескриптор, который остался открытым, это может помочь. В моей экосистеме мы запускаем Parse Server в качестве промежуточного программного обеспечения с Express-сервером, но это может относиться к любому, кому нужно запустить отдельный сервер с тестами, но не может закрыть какой-то сокет или порт в конце. Я _ верю_, что проблема, вызывающая ужасную ошибку «Jest не завершилась одна секунда ...» для нас, была результатом неправильного закрытия адаптера Parse MongoDB.

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

Скрипт NPM (package.json):

"scripts": {
    "test": "npm start & ./listen_on_port_5000.sh && jest test && kill $(lsof -t -i tcp:5000)",
}

listen_on_port_5000.sh

while ! nc -z localhost 5000
do
    sleep 0.5
done

Так, как это работает?

  1. npm start run - это обычная команда, которую мы выполняем для запуска нашего сервера с помощью Express и Parse.
  2. Поскольку мы знаем, что сервер всегда запускается на порту 5000, мы запускаем сценарий start в фоновом режиме и запускаем отдельный процесс, запускающий сценарий оболочки ( listen_on_port_5000.sh ), чтобы дождаться загрузки сервера. .
  3. Как только сценарий прослушивателя обнаруживает что-либо, работающее на порту 5000, сценарий npm переходит к команде jest (все время, пока сервер Express запущен и работает).
  4. Когда Jest завершает работу, последний сценарий запускает сценарий kill чтобы закрыть сервер, работающий на порту 5000.

У меня были тесты, которые проверяли автоматически сгенерированные соединения http-сервера и socket.io.
Тесты прошли нормально на моей машине с Windows, но не завершились из-за того, что не вышли на моем сервере Jenkins.

Я правильно закрывал и сервер socket.io, и http-сервер в конце теста, но я не закрывал клиентов. После того, как я добавил очистку для клиентов, тесты успешно завершились самостоятельно как на моей машине разработчика, так и на сервере CI.

Тесты работали бы без закрытия клиентов, если бы я использовал --forceExit , но, в конце концов, настоящая проблема заключалась в неправильной очистке.

Я также обнаружил, что --detectOpenHandles ничего не выводит.

Я столкнулся с той же проблемой с хуками globalSetup и globalTeardown , но я не могу найти никаких процессов, оставшихся без присмотра. Я добавил done() в конец всех тестов и останавливаю свой сервер во время разборки.

jest --runInBand --detectOpenHandles ничего не выводит на консоль.

Я столкнулся с той же проблемой с хуками globalSetup и globalTeardown , но я не могу найти никаких процессов, оставшихся без присмотра. Я добавил done() в конец всех тестов и останавливаю свой сервер во время разборки.

jest --runInBand --detectOpenHandles ничего не выводит на консоль.

Столкнувшись с той же проблемой, попытался закрыть соединение sequelize, не повезло.
Хотя проблема может быть не в шутке, но ее основная проблема в том, что он не показывает, какие процессы активны. --detectOpenHandles ничего не печатает: confused:
Вверху, если мы используем --forceExit, отображается сообщение об использовании --detectOpenHandles
Ирония: -1:

У меня тоже была эта проблема

В итоге я использовал https://www.npmjs.com/package/why-is-node-running, входя в систему beforeAll

import log from 'why-is-node-running';

afterAll(async () => {
  //normal cleanup things
  await new Promise(resolve => {
    setTimeout(() => {
      log()
      resolve()
    }, 4000)
  })
}

Оказывается, поскольку я использовал jest.resetModules, мне пришлось повторно импортировать модуль, который использовал соединение pg, и закрыть его там тоже.

У меня тоже такая проблема. Чтобы дать некоторый контекст, я использую SuperTest для тестирования e2e с MongoMemoryServer .
Моя установка и разборка выглядят так:

let mongoServer;

beforeAll(async (done) => {
  mongoServer = new MongoMemoryServer({ instance: { port: 26016 } });
  const uri = await mongoServer.getUri();
  process.env.MONGODB_URI = uri;
  done();
});

afterAll(async (done) => {
  await mongoServer.stop();
  done();
}); 

Ничего необычного, что могло бы свидетельствовать о том, что я неправильно слежу за документацией.
Я начал устранение неполадок с просмотра Activity Monitor в MacOS. Кажется, что есть два процесса node , которые все еще работают, пока выполняется jest.
image
Однако, как только я отменяю / выхожу из тестового прогона, процессы также завершаются.

Я собираюсь исследовать дальше, отобрав процессы узлов и посмотрим, что именно их порождает. Я обновлю здесь свои выводы.

РЕДАКТИРОВАТЬ: Связанная проблема № 1456 - похоже, что это основная проблема NodeJS. tl; dr - добавьте флаг --forceExit в свой тестовый скрипт в package.json

Привет! Похоже, вы еще не отключились от базы данных. Я пробовал mongoose.disconnect() в функции afterAll() и он больше не показывает такое сообщение.

Screenshot from 2020-07-21 11-53-28

@BigsonLvrocha спасибо за идею re: why-is-node-running ! В моем случае этот инструмент показал мне, что redux-state-sync инициализируется в тестах, в которых есть бесконечный цикл для прослушивания обновлений Redux. --detectOpenHandles мне тоже ничего не вывел.

Я тестирую свое приложение React Native и получаю это. Я получаю данные из BE и использую moxios . Затем я отправляю действие по обновлению магазина. Я использую "jest": "^26.4.2",

  test('dispatch paperPlanes/set action correctly updates the store', async done => {
    // Mock the response to /paperPlane/list
    moxios.wait(() => {
      const request = moxios.requests.mostRecent();
      request.respondWith({
        status: 200,
        response: expectedResponse,
      });
    });

    // Execute the api call to /paperPlane/list
    const res = await axios.get('/paperplane/list');

    const action = actionCreators.paperPlanes.set(res.data.paper_planes);
    store.dispatch(action);

    const newState = store.getState();
    expect(newState.paperPlanes.paperPlanes).toEqual(
      expectedResponse.paper_planes,
    );
    done();
  });

У меня есть эта ошибка в нескольких тестах шутки. Я закрываю экспресс-сервер правильно с помощью server.close ().

На тесте я решил проблему с закрытием соединения мангуста с помощью connection.disconnect ().

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

Способ состоит в том, чтобы анализировать от случая к случаю.

Что делать, если я не вызываю базу данных? Что делать, если я вызываю внешний ресурс, над которым не имею контроля? Как мне "закрыть"?

@YounesTea, у вас может быть вызов async / await в вашем коде.
Попробуйте позвонить в done() после того, как все будет хорошо 😉

it("Should test something", async (done) => {
  // Sends request...
  const req = await request(app).get("/someEndpoint");
  expect(req).toBeTruthy();
  done();
});

@YounesTea, у вас может быть вызов async / await в вашем коде.
Попробуйте позвонить done() после того, как вы, хорошо, сделали

it("Should test something", async (done) => {
  // Sends request...
  const req = await request(app).get("/someEndpoint");
  expect(req).toBeTruthy();
  done();
});

У меня есть async / awaits, и я уже использую обратный вызов done () в тестах, включая beforeAll и afterAll.
Проблема не устранена ...

beforeAll (async () => {
ждать firebase.firestore (). enableNetwork ();
});

afterAll (async () => {
ждать firebase.firestore (). disableNetwork ();
});

Это не работает. Однако это работает:

afterAll(async () => {
  await app.delete()
})

в монго я решил это:

`afterAll(async(done) => {
  // Closing the DB connection allows Jest to exit successfully.
  await mongoose.connection.close()
  done()
})`
Была ли эта страница полезной?
0 / 5 - 0 рейтинги