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

Jest/JavaScript:如何仅在测试失败时显示测试用例日志?

当然可以实现!这里有几种实用方案帮你搞定Jest只在测试失败时打印日志的需求

针对你用Jest+Selenium做E2E测试遇到的无提示失败、调试难的问题,完全可以通过自定义日志逻辑,让日志只在对应测试用例失败时才输出,不会污染成功测试的控制台。下面是两种落地性很强的方案:

方案一:自定义缓存式Logger + Jest测试钩子

核心思路是先把测试过程中的日志缓存起来,等测试结束后判断是否失败,再决定要不要打印缓存的日志。

步骤1:实现自定义Logger

创建一个简单的Logger类,内部维护日志缓存,提供日志方法和输出缓存的方法:

class ConditionalLogger {
  constructor() {
    this.logs = [];
  }

  info(message) {
    this.logs.push(`[INFO] ${message}`);
  }

  error(message) {
    this.logs.push(`[ERROR] ${message}`);
  }

  // 输出所有缓存的日志并清空
  flushLogs() {
    this.logs.forEach(log => console.log(log));
    this.logs = [];
  }

  // 清空缓存不输出
  clearLogs() {
    this.logs = [];
  }
}

// 每个测试用例实例化一个独立的logger,避免跨用例污染
let logger;

步骤2:结合Jest的beforeEach和afterEach钩子控制日志输出

在测试套件中加入钩子,每个测试前初始化logger,测试结束后根据结果决定是否输出日志:

describe('Selenium E2E Tests', () => {
  beforeEach(() => {
    // 每个测试用例开始时创建新的logger实例
    logger = new ConditionalLogger();
  });

  afterEach(async () => {
    // 获取当前测试的结果状态
    const currentTest = expect.getState().currentTestName;
    const testResults = expect.getState().testResults;
    const failedTest = testResults.find(result => result.name === currentTest && !result.status);

    if (failedTest) {
      // 如果测试失败,先打印缓存的日志,再输出错误信息(符合你要的日志在错误前的需求)
      console.log(`\n--- Logs for failed test: ${currentTest} ---`);
      logger.flushLogs();
      console.log('--- End of logs ---');
    } else {
      // 测试成功,清空缓存不输出
      logger.clearLogs();
    }
  });

  it('case 1', async () => {
    logger.info('Starting case 1: Navigating to login page');
    // Selenium操作:await driver.get('/login');
    logger.info('Entering username');
    // Selenium操作:await driver.findElement(By.id('username')).sendKeys('test');
    
    // 模拟失败
    expect(1).toBe(2);
  });

  it('case 2', async () => {
    logger.info('Starting case 2: Checking dashboard');
    // Selenium操作:await driver.get('/dashboard');
    logger.info('Verifying dashboard title');
    
    // 测试成功,日志不会输出
    expect(true).toBe(true);
  });
});

方案二:利用Jest的testFailed事件(更简洁)

Jest提供了全局的测试事件钩子,你可以监听testFailed事件,在测试失败时主动打印对应测试的日志。这种方式不需要自定义Logger,直接用Jest的全局日志收集:

步骤1:在Jest配置或测试入口文件中监听事件

// 在jest.setup.js(或你的测试入口文件)中添加
jest.config = {
  setupFilesAfterEnv: ['./jest.setup.js']
};

// 全局维护一个测试日志映射,key是测试名称,value是日志数组
global.testLogs = new Map();

// 监听测试失败事件
jest.testFailed = (test) => {
  const logs = global.testLogs.get(test.name);
  if (logs) {
    console.log(`\n--- Logs for failed test: ${test.name} ---`);
    logs.forEach(log => console.log(log));
    console.log('--- End of logs ---');
    // 输出后删除,避免内存占用
    global.testLogs.delete(test.name);
  }
};

// 监听测试成功事件,删除对应日志
jest.testPassed = (test) => {
  global.testLogs.delete(test.name);
};

步骤2:在测试用例中收集日志

describe('Selenium E2E Tests', () => {
  beforeEach(() => {
    // 初始化当前测试的日志数组
    global.testLogs.set(expect.getState().currentTestName, []);
  });

  const log = (message) => {
    const currentTest = expect.getState().currentTestName;
    global.testLogs.get(currentTest).push(`[INFO] ${message}`);
  };

  it('case 1', async () => {
    log('Starting case 1: Navigating to login page');
    // Selenium操作
    log('Entering username');
    
    expect(1).toBe(2); // 模拟失败
  });

  it('case 2', async () => {
    log('Starting case 2: Checking dashboard');
    // Selenium操作
    
    expect(true).toBe(true); // 成功,日志被删除不会输出
  });
});

额外优化建议

  • 可以把Selenium的关键操作封装成带日志的函数,比如await clickElement(driver, By.id('submit'), 'Clicking submit button'),这样不用每次手动加日志,减少重复代码。
  • 如果用Winston、Pino这类专业日志库,也可以通过动态调整日志级别或者自定义传输器(transporter)来实现类似逻辑:测试成功时设置日志级别为silent,失败时改为info/debug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:38:43