Jest: لم تخرج Jest ثانية واحدة بعد اكتمال التشغيل التجريبي.

تم إنشاؤها على ٢٦ أكتوبر ٢٠١٨  ·  33تعليقات  ·  مصدر: facebook/jest

تصلني هذه الرسالة في كل مرة أستخدم فيها أي مكتبات تعتمد على الوعود.

🐛 تقرير الشوائب

لم تخرج Jest ثانية واحدة بعد اكتمال التشغيل التجريبي.

يعني هذا عادةً وجود عمليات غير متزامنة لم يتم إيقافها في اختباراتك. ضع في اعتبارك تشغيل Jest مع --detectOpenHandles لاستكشاف هذه المشكلة وإصلاحها.

لإعادة إنتاج

لدي وظيفة تحتاج إلى تقديم طلب لواجهة برمجة تطبيقات خارجية ، وبنفس الطريقة فقط احفظها في قاعدة البيانات دون انتظار الرد.

لا أريد الانتظار حتى تتم عملية الحفظ ، لكنني مضطر إلى تغيير سلوك تطبيقي لاختباره من خلال الدعابة. ، أو أحتاج إلى إغلاق الاتصال ، وإيقاف الخادم حتى يعمل الكود الخاص بي .

سلوك متوقع

دعابة مقتطعة للتوقف والعودة إلى وحدة التحكم الخاصة بي.

رابط للإعادة أو الريبو (يُشجع بشدة)

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 لإعداد قاعدة البيانات إلى حالة معروفة في 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();
});

تضمين التغريدة
تضمين التغريدة

أضفت مثالا.

ال 33 كومينتر

حاول وضع "تم" داخل رد الاتصال من وظيفة الاختبار على النحو التالي:

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

بالإضافة إلى ذلك ، إذا تم الإبقاء على الاتصال مفتوحًا ، فسيؤدي هذا أيضًا إلى إيقاف اكتمال الاختبار ، لذلك يوصى أيضًا بإغلاق أي اتصال مفتوح.

شكرا لك ExoMemphiz ، ولكن رد الاتصال هذا ، من أين يجب أن أصل؟

إنه عميق جدًا داخل الخادم.

انتقلت إلى آفا ، إنها تعمل خارج الصندوق 👍

حسنًا ، أخي الدنماركي :)

تكمن المشكلة في أنني أستخدم النمس لحفظ شيء غير متزامن عندما أسمي هذا api ، ولا يمكنني الوصول إلى هذا الرمز لمعرفة متى ينتهي حفظ المستند داخل mongo.

await server.inject

في الواقع ، ينتظر الكود أعلاه الرد فقط ، وهو يعمل ، ولكن مازحًا يشكو من حفظ النمس ، فهو لا يزال قيد التقدم في الحفظ خلف الكواليس.

حاولت فصل النمس وإغلاق كل اتصال ، لكنه لم ينجح.

لقد تلقيت نفس الخطأ في أحد اختبارات التكامل الخاصة بي. في ذلك ، كنت أستخدم نموذج Sequelize لإعداد قاعدة البيانات إلى حالة معروفة في 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();
});

تضمين التغريدة
تضمين التغريدة

أضفت مثالا.

لقد تلقيت نفس الخطأ في أحد اختبارات التكامل الخاصة بي. في ذلك ، كنت أستخدم نموذج Sequelize لإعداد قاعدة البيانات إلى حالة معروفة في beforeAll . كان الإصلاح هو استدعاء close على مثيل Sequelize المتصل بالنموذج في رد الاتصال afterAll . آمل أن يساعد هذا شخص آخر.

ما هو إصدار Sequelize الذي تستخدمه؟ أحصل على sequelizeInstance.close() ليست وظيفة.

لقد تلقيت نفس الخطأ في أحد اختبارات التكامل الخاصة بي. في ذلك ، كنت أستخدم نموذج Sequelize لإعداد قاعدة البيانات إلى حالة معروفة في beforeAll . كان الإصلاح هو استدعاء close على مثيل Sequelize المتصل بالنموذج في رد الاتصال afterAll . آمل أن يساعد هذا شخص آخر.

هل يمكنك إظهار الكود الخاص بك؟

مرحبًا ، لقد تلقيت نفس الخطأ ، مع @ dhurlburtusa tip ، كان الرمز الخاص بي هو 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 هو الوظيفة التي تتصل بالفعل بمثيل قاعدة البيانات.

لقد تلقيت نفس الخطأ في أحد اختبارات التكامل الخاصة بي. في ذلك ، أستخدم 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 أقوم بالاتصال بـ db وأعيد وظيفة ترجع الوعد. وبالمثل في teardownTests أقوم بإغلاق اتصال db وأعد وظيفة ترجع الوعد.

كنت أواجه هذه المشكلة مع 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 لم يخرج ثانية واحدة ..." بالنسبة لنا كان نتيجة عدم إغلاق محول MongoDB الخاص بـ Parse بشكل صحيح.

لذا للتغلب على هذه المشكلة ، قمت بتجريد تهيئة الخادم تمامًا من مجموعة اختبار jest وأنشأت برنامجًا نصيًا خاصًا 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 وهو الأمر العادي الذي سنقوم بتشغيله لبدء تشغيل خادمنا باستخدام Express و Parse.
  2. نظرًا لأننا نعلم أن الخادم يبدأ دائمًا على المنفذ 5000 ، فإننا نشغل البرنامج النصي start في الخلفية ونبدأ عملية منفصلة تقوم بتشغيل برنامج shell script ( 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 بطباعة أي شيء إلى وحدة التحكم.

تواجه نفس المشكلة حاول إغلاق اتصال تكملة ، لا حظ هناك.
على الرغم من أن المشكلة قد لا تتعلق بالمزح ولكن مشكلتها الرئيسية هي أنها لا تعرض العمليات النشطة. --detectOpenHandles لا يطبع أي شيء: confused:
في الجزء العلوي ، إذا استخدمنا --forceExit ، فستظهر رسالة لاستخدام --detectOpenHandles
السخرية: -1:

لقد كنت أواجه هذه المشكلة أيضًا

انتهى بي الأمر باستخدام https://www.npmjs.com/package/why-is-node-running تسجيل الدخول قبل الكل

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 .
يبدو الإعداد و teardown كما يلي:

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 لا تزال تعمل أثناء تشغيل المزاح.
image
ومع ذلك ، بمجرد إلغاء / إنهاء التشغيل التجريبي ، يتم إنهاء العمليات أيضًا.

سأقوم بمزيد من الاستقصاء عن طريق أخذ عينات من عمليات العقدة وأرى بالضبط ما يولدها. سوف أقوم بتحديث النتائج التي توصلت إليها هنا.

تحرير: المشكلة ذات الصلة رقم 1456 - يبدو أنها مشكلة أساسية في NodeJS. tl ؛ dr - أضف علامة --forceExit إلى نص الاختبار الخاص بك في package.json

أهلا! يبدو أنك لم تقم بعد بقطع الاتصال بقاعدة البيانات. لقد جربت وظيفة mongoose.disconnect() في afterAll() وهي لا تظهر رسالة كهذه بعد الآن.

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

BigsonLvrocha أشكرك على هذه الفكرة لإعادة: 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 ().

في الاختبار ، قمت بحل مشكلة إغلاق اتصال النمس بشكل صحيح باستخدام الاتصال. قطع الاتصال ().

لكن الاختبارات الأخرى تقدم الرسالة حتى الآن. لقد لاحظت أن جميع اختباراتي التي تستخدم الحزمة الفائقة تحافظ على الرسالة.

الطريقة هي تحليل كل حالة على حدة.

ماذا لو لم أستدعي قاعدة بيانات؟ ماذا لو اتصلت بمورد خارجي ليس لدي سيطرة عليه؟ كيف "أغلق"؟

YounesTea قد يكون لديك مكالمة غير
حاول الاتصال بـ done() بعد أن تكون قد انتهيت 😉

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

YounesTea قد يكون لديك مكالمة غير
حاول الاتصال بـ done() بعد أن تكون قد انتهيت

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

لدي غير متزامن / ينتظر وأنا أستخدم بالفعل رد الاتصال المنجز () في الاختبارات بما في ذلك beforeAll و afterAll.
استمرت المشكلة ...

beforeAll (غير متزامن () => {
في انتظار firebase.firestore (). enableNetwork () ؛
}) ؛

afterAll (غير متزامن () => {
في انتظار firebase.firestore (). disableNetwork () ؛
}) ؛

هذا لا يعمل. ومع ذلك ، هذا واحد يعمل:

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

في mongo لقد حللت هذا:

`afterAll(async(done) => {
  // Closing the DB connection allows Jest to exit successfully.
  await mongoose.connection.close()
  done()
})`
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات