You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest测试Nest.js应用时异步未等待导致测试报错

Nest.js + Jest 测试异步操作无法正常完成的问题

我用Jest测试Nest.js微服务应用时,在使用lastValueFrom、Promise.all和timeout组合时遇到测试无法正常结束的问题,报错信息如下:

Cannot log after tests are done. Did you forget to wait for something async in your test?

场景说明:我有一个执行异步操作的formattedProduct函数,在getProductsList方法中通过Promise.all等待所有该函数的Promise完成。测试代码通过NATS发送请求并等待响应,但测试始终无法正常收尾。


代码片段

1. formattedProduct函数

async formattedProduct(
  product_id: string,
  product: any,
  output_template: CardProductTemplate | PageProductTemplate,
  curCityId: any = false,
  customerId: any = false,
){
  // 其他业务逻辑代码...
  console.log('product calculated');
  return product;
}

2. getProductsList服务方法

public async getProductsList(params: GetProductsListDto) {
  // 其他前置方法逻辑...

  const promisesFormattedProduct: Promise<any>[] = [];
  products.forEach((product) => {
    promisesFormattedProduct.push(
      this.formattedProduct(
        product.id,
        product,
        new CardProductTemplate(),
        params.city_id,
        params.customer_id,
      ),
    );
  });
 
  const formatted_products = await Promise.all(promisesFormattedProduct);
 
  const result = {
    formatted_products,
  };

  return result;
}

3. 控制器代码

@MessagePattern([
  'api-gateway.common.getProductsList',
  'api-gateway.common.getProductsListByBrand',
  'api-gateway.common.getUsedProductsList',
  'api-gateway.common.getSimilarProductsList',
])
async getProductsList(params: GetProductsListDto) {
  const products= await this.productService.getProductsList(params);
  return products;
}

4. 测试文件

import { Test, TestingModule } from '@nestjs/testing';
import { INestMicroservice } from '@nestjs/common';
import { Transport, ClientProxyFactory, ClientProxy } from '@nestjs/microservices';
import { AppModule } from '@src/app.module'; 
import { lastValueFrom } from 'rxjs/internal/lastValueFrom';
import { timeout } from 'rxjs';

describe('ProductController (NATS)', () => {
  let app: INestMicroservice;
  let client: ClientProxy;

  beforeAll(async () => {
    const moduleRef: TestingModule = await Test.createTestingModule({
      imports: [AppModule],  
    }).compile();

    app = moduleRef.createNestMicroservice({
      transport: Transport.NATS,
      options: {
        servers: ['nats://nats:4222'],
      },
    });

    await app.listen();

    client = ClientProxyFactory.create({
      transport: Transport.NATS,
      options: {
        servers: ['nats://nats:4222'],
      },
    });

    await client.connect();
  });

  afterAll(async () => {
    // if (client) {
    //   await client.close();
    // }
    // if (app) {
    //   await app.close();
    // }

  });

  it('should return response for unauthorized', async () => {
    const params = {
      rate_id: 643,
      category_id: '0b5d5269-5e79-11e3-bd86-002590552cc0',
      page: 0,
      onpage: 20,
      sort_by: 'relevance',
      sort_order: 'asc',
      filter: {},
      city_id: '90',
      customer_id: null,
      selection_type: 'from_category'
    };

    const response = await lastValueFrom(client.send('api-gateway.common.getProductsList', params).pipe(timeout(60000)));

    console.log('response get');
    expect(response).toBeDefined();

    return;
  }, 60000);
});

问题原因及解决方法

核心原因

测试完成后仍有未收尾的异步操作在后台运行(比如未关闭的连接、未被正确等待的Promise),导致console.log在测试结束后触发,触发Jest的报错逻辑。

解决步骤

  1. 恢复afterAll中的连接关闭逻辑
    取消afterAll里的注释,确保测试结束后关闭NATS客户端和微服务应用,彻底终止所有异步资源:

    afterAll(async () => {
      await client.close();
      await app.close();
    });
    
  2. 检查formattedProduct内部的异步逻辑
    确保formattedProduct函数内的所有异步操作(比如数据库查询、外部API调用)都被正确await,没有遗漏的后台任务。如果存在未被等待的异步代码,会导致Promise.all提前完成,但实际还有任务在运行。

  3. 验证Promise.all的执行完整性
    可以在Promise.all后添加日志,确认所有格式化任务确实已经完成:

    const formatted_products = await Promise.all(promisesFormattedProduct);
    console.log('All products formatted'); // 确认所有异步任务完成
    
  4. 测试环境禁用不必要的日志
    可以在测试中临时禁用console.log,避免测试结束后日志干扰Jest的判断:

    beforeEach(() => {
      jest.spyOn(console, 'log').mockImplementation(() => {});
    });
    
    afterEach(() => {
      jest.restoreAllMocks();
    });
    

内容的提问来源于stack exchange,提问作者Sergei Illarionov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 20:35:02