Не удается войти в систему после выполнения тестов в jestjs

#unit-testing #testing #jestjs

#модульное тестирование #тестирование #jestjs

Вопрос:

Я написал тестовые примеры для signin API с использованием jest. После завершения всех пяти тестов тестового костюма jest выдает мне следующую ошибку в журнале.

Может ли кто-нибудь объяснить, почему это так и как это исправить?

КОД: (signup.test.ts)

 import request from 'supertest';
import { TYPES } from '../src/inversify.types'
import { Application } from '../src/app/Application'
import { container } from '../src/inversify.config'
import dotenv from 'dotenv'
import { RESPONSE_CODE } from '../src/utils/enums/ResponseCode'
import { RESPONSE_MESSAGES } from '../src/utils/enums/ResponseMessages'
import { UserSchema } from '../src/components/user/User';
// import jwt from 'jsonwebtoken';
var application: Application

describe("POST / - SIGNUP endpoint", () => {
    // var testusers: any;
    //This hook is executed before running all test cases, It will make application instance, make it to listen 
    // on it on port 3000 and add test document in DB
    beforeAll(async () => {
        // Make enviroment variables available throughout the application
        dotenv.config();
        // Getting application instance using iversify container
        application = container.get<Application>(TYPES.Application);
        // Initialize frontside of application
        await application.bootstrap();
        // Starting Application server on given port
        await application.listen(3000);
    });

    afterAll(
        //This hook is executed after running all test cases and delete test document in database
        async () =>{
        const res = await UserSchema.deleteMany({ Name: { $in: [ "Test User", "Test" ] } });
        // `0` if no docs matched the filter, number of docs deleted otherwise
        console.log('---------------------->>>>>>>>>>>>>>>>>>>', (res as any).deletedCount);
    }
    )

    it("Signup for user that don't exists", async () => {
        const response = await request(application.getServer()).post('/user/signup')
        .send({
            "Email": JSON.parse(process.env.TEST_USER).Email,
            "Name": "Test User",
            "Password": process.env.TEST_ACCOUNTS_PASSWORD
            })
            expect(response.status).toBe(RESPONSE_CODE.CREATED);
            expect(JSON.parse(response.text)).toEqual(expect.objectContaining({ 
                Message: RESPONSE_MESSAGES.ADDED_SUCESSFULLY, 
                Data: expect.objectContaining({
                    Name: 'Test User',
                    Country: '',
                    PhoneNumber: '',
                    // Password: '$2b$10$nIHLW/SA73XLHoIcND27iuODFAArOvpch6FL/eikKT78qbShAl6ry',
                    Dob: '',
                    Role: 'MEMBER',
                    IsEmailVerified: false,
                    IsBlocked: 'ACTIVE',
                    IsTokenSent: false,
                    twoFAStatus: false,
                    // _id: '5c812e2715e0711b98260fee',
                    Email: JSON.parse(process.env.TEST_USER).Email
                })
            })
            );
        console.log('*** Signup for user that don't exists *** response', response.text, 'response status', response.status);   
    });
    it("Signup for user that exists", async () => {
        const response = await request(application.getServer()).post('/user/signup')
        .send({
            "Email": JSON.parse(process.env.TEST_USER).Email,
            "Name": "Test User",
            "Password": process.env.TEST_ACCOUNTS_PASSWORD
            })
            expect(response.status).toBe(RESPONSE_CODE.CONFLICT);
            expect(JSON.parse(response.text)).toEqual({ 
                Message: RESPONSE_MESSAGES.ALREADY_EXISTS
            })
        console.log('*** Signup for user that don't exists *** response', response.text, 'response status', response.status);   
    });

});
  

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

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

Не удается войти в систему после выполнения тестов. Вы забыли дождаться чего-то асинхронного в вашем тесте?

 Attempted to log "{ accepted: [ 'unverifiedtestuser@abc.com' ],
      rejected: [],
      envelopeTime: 621,
      messageTime: 867,
      messageSize: 906,
      response: '250 2.0.0 OK  1551945300 f6sm5442066wrt.87 - gsmtp',
      envelope:
       { from: 'abc@gmail.com',
         to: [ 'unverifiedtestuser@abc.com' ] },
      messageId: '<45468449-b5c8-0d86-9404-d55bb5f4g6a3@gmail.com>' }".




at CustomConsole.log (node_modules/jest-util/build/CustomConsole.js:156:10)
  at src/email/MailHandler.ts:2599:17
  at transporter.send.args (node_modules/nodemailer/lib/mailer/index.js:226:21)
  at connection.send (node_modules/nodemailer/lib/smtp-transport/index.js:247:32)
  at callback (node_modules/nodemailer/lib/smtp-connection/index.js:435:13)
  at stream._createSendStream (node_modules/nodemailer/lib/smtp-connection/index.js:458:24)
  at SMTPConnection._actionSMTPStream (node_modules/nodemailer/lib/smtp-connection/index.js:1481:20)
  at SMTPConnection._responseActions.push.str (node_modules/nodemailer/lib/smtp-connection/index.js:968:22)
  at SMTPConnection._processResponse (node_modules/nodemailer/lib/smtp-connection/index.js:764:20)
  at SMTPConnection._onData (node_modules/nodemailer/lib/smtp-connection/index.js:570:14)
  

Комментарии:

1. Можете ли вы опубликовать код для самого теста? Это поможет диагностировать происходящее. Вот пример асинхронности Jest и пример проблемы с GitHub , чтобы дать вам некоторое представление о вещах, которые могут вызывать ошибки такого типа.

2. @ty2k. Я обновил код, пожалуйста, проверьте. Я уже оформил документы, но не могу выяснить

3. Ознакомьтесь с разделом обратных вызовов в документации Jest по async, в частности с разделом, который передается done в качестве аргумента. Также есть этот пост в выпуске Supertest , который имеет ту же проблему, что и у вас. По сути, ваши тесты завершаются до завершения работы вашего сервера.

Ответ №1:

Я использовал тестовый пример react-native по умолчанию (см. Ниже), когда Cannot log after tests are done произошло.

 it('renders correctly', () => {
  renderer.create(<App />);
});
  

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

 it('renders correctly', async () => {
  renderer.create(<App />);
});
  

И это сработало. Однако я очень мало представляю, что такое внутренняя работа.

Комментарии:

1. К сожалению, у меня не работает! Примечание: в App.js Я просто отображаю конфигурацию навигационного компонента «NavigationContainer»

Ответ №2:

Если вы используете в своем коде тип async / await, то эта ошибка может возникнуть при вызове async функции без await ключевого слова.

В моем случае я определил функцию, подобную приведенной ниже,

 async getStatistics(headers) {
    ....
    ....
    return response;
}
  

Но я вызвал этот метод как getStatistics(headers) вместо await getStatistics(headers) .

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

Ответ №3:

В моем случае при использовании nodejs jest supertest проблема заключалась в том, что когда я import app from "./app" обращаюсь к своему тестовому файлу, чтобы что-то сделать с помощью supertest ( request(app) ), я фактически импортирую с помощью app.listen() , потому что при экспорте app экспорт также учитывается app.listen() , но нам не нужны app.listen() тесты, и это выдает ошибку

«Не удается войти в систему после выполнения тестов.Вы забыли дождаться чего-то асинхронного в вашем тесте?»

Здесь все в одном файле (вот в чем проблема!)

 const app = express();

app.use(express.json());

// ROUTES
app.get("/api", (req, res) => {
  res.json({ message: "Welcome to Blog API!" });
});

app.use("/api/users", usersRoutes);
app.use("/api/blogs", blogsRouter);

// The server will start only if the connection to database is established
mongoose
  .connect(process.env.MONGO_URI!)
  .then(() => {
    console.log("MongoDB est connecté");

    const port = process.env.PORT || 4000;
    app.listen(port, () => console.log(`The server is running on port: ${port}`));
  })
  .catch(err => {
    console.log(err);
  });

export default app;
  

Чтобы решить эту проблему, я создал 2 отдельные папки:

// 1) app.ts

Куда я помещаю все материалы для своего const app = express() , маршруты и т.д. И экспортирую приложение

 dotenv.config();

const app = express();

app.use(express.json());

// ROUTES
app.get("/api", (req, res) => {
  res.json({ message: "Welcome to Blog API!" });
});

app.use("/api/users", usersRoutes);
app.use("/api/blogs", blogsRouter);

export default app;
  

// 2) index.ts

Куда я помещаю app.listen() and mongoose.connection() и импортирую app

 *import mongoose from "mongoose";
import app from "./app";

// The server will start only if the connection to database is established

mongoose
  .connect(process.env.MONGO_URI!)
  .then(() => {
    console.log("MongoDB est connecté");

    const port = process.env.PORT || 4000;
    app.listen(port, () => console.log(`The server is running on port: ${port}`));
  })
  .catch(err => {
    console.log(err);
  });*
  

Комментарии:

1. Ссылка . на 32-й минуте он объясняет проблему

Ответ №4:

Это случилось со мной, потому что у меня был бесконечный цикл while (true) . В моем случае я смог добавить метод для установки значения цикла на основе пользовательского ввода, вместо значения true по умолчанию.

Ответ №5:

Лично мне также нужно было добавить await перед expect() вызовом, чтобы остановить эту ошибку (и async перед test() функцией обратного вызова).

Также вызвано и исправлено, что Jest не обнаруживал покрытие в строках кода, выдававшего ошибку!

 test("expect error to be thrown for incorrect request", async () => {
  await expect(
  // ^ added this
    async () => await getData("i-made-this-up")
  ).rejects.toThrow(
    "[API] Not recognised: i-made-this-up"
  );
});
  

getData() возвращает вызов Axios, и в этом случае ошибка перехватывается catch и повторно выдается.

 const getData = async (id) => {
  return await axios
    .get(`https://api.com/some/path?id=${id}`)
    .then((response) => response.data)
    .catch((error) => {
      if (error?.response?.data?.message) {
        console.error(error) // Triggered the error
        throw new Error("[API] "   error.response.data.message);
      }

      throw error;
    });
};
  

Ответ №6:

Я решил это с помощью переменных env:

 if (process.env.NODE_ENV !== 'test') {
  db.init().then(() => {
    app.listen(PORT, () => {
      console.log('API lista por el puerto ', PORT)
    })
  }).catch((err) => {
    console.error(err)
    process.exit(1)
  })
} else {
  module.export = app
}  

Ответ №7:

В моем случае ошибка была вызвана тем, что асинхронное соединение Redis все еще подключено к сети. Только что добавил метод afterall для выхода из Redis и смог снова просмотреть журнал.

Работа с Typescript 4.4.2:

 test("My Test", done => {
    let redisUtil: RedisUtil = new RedisUtil();
    let redisClient: Redis = redisUtil.redis_client();
    done();
});

afterAll(() => {
    redisClient.quit();
});
  

Ответ №8:

Я столкнулся с теми же предупреждениями. Однако исправление немного странное:

Скрипт модульного тестирования jest импортирует функцию (которая не экспортируется из src /). После того, как я добавил export в тестируемую функцию. Ошибка исчезает.

Ответ №9:

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

jest.setTimeout();

В моем случае я просматриваю вызовы API и веду журнал, поэтому он будет расширяться после тайм-аута jest по умолчанию, поэтому я получал ошибку.

Ответ №10:

У меня была похожая проблема:

 Cannot log after tests are done. Did you forget to wait for something async in your test?
Attempted to log "Warning: You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. ".
  

Это произошло из-за отсутствия static ключевого слова. Этот код вызвал проблему:

 class MyComponent extends React.Component<Props, State> {
  propTypes = {
    onDestroy: PropTypes.func,
  }
}
  

Это должно было быть:

 class MyComponent extends React.Component<Props, State> {
  static propTypes = {
    onDestroy: PropTypes.func,
  }
}