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

Cypress执行测试后未生成cypress-mochawesome-report的解决方法

Cypress集成cypress-mochawesome-reporter不生成报告的问题

环境与配置信息

使用版本:

  • cypress: ^13.7.2
  • cypress-mochawesome-reporter: ^3.8.2

已完成的配置步骤:

  1. 安装依赖:npm i --save-dev cypress-mochawesome-reporter
  2. 配置cypress.config.ts(代码如下)
  3. 在e2e.ts中导入cypress-mochawesome-reporter/register
  4. 在index.ts中导入cypress-mochawesome-reporter/cucumberSupport

cypress.config.ts 配置

import eyesPlugin from '@applitools/eyes-cypress';
import { addCucumberPreprocessorPlugin } from '@badeball/cypress-cucumber-preprocessor';

import createBundler from '@bahmutov/cypress-esbuild-preprocessor';
import { defineConfig } from 'cypress';
import * as env from './cypress.env.json';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { createEsbuildPlugin } = require('@badeball/cypress-cucumber-preprocessor/esbuild');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { NodeModulesPolyfillPlugin } = require('@esbuild-plugins/node-modules-polyfill');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { verifyDownloadTasks } = require('cy-verify-downloads');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { beforeRunHook, afterRunHook } = require('cypress-mochawesome-reporter/lib');


export default eyesPlugin(
    defineConfig({
        reporter: 'cypress-mochawesome-reporter',
        reporterOptions: {
            reportDir: '/Users/alitaha/Development/frontend/cypress/reports',
            overwrite: true,
            html: true,
            json: true,
            charts: true,
            reportPageTitle: 'custom-title',
            embeddedScreenshots: true,
            inlineAssets: true,
            saveAllAttempts: false,
        },
        e2e: {
            baseUrl: 'https://frontend-release-green.com/',
            specPattern: '**/*.feature',
            env,
            defaultCommandTimeout: 20000,
            experimentalRunAllSpecs: true,
            requestTimeout: 20000,
            viewportWidth: 1920,
            viewportHeight: 1080,
            screenshotOnRunFailure: false,
            video: false,
            async setupNodeEvents(
                on: Cypress.PluginEvents,
                config: Cypress.PluginConfigOptions
            ): Promise<Cypress.PluginConfigOptions> {
                // This is required for the preprocessor to be able to generate JSON reports after each run, and more,
                await addCucumberPreprocessorPlugin(on, config);
                on(
                    'file:preprocessor',
                    createBundler({
                        plugins: [NodeModulesPolyfillPlugin(), createEsbuildPlugin(config)],
                    })
                );
                on('before:run', async (details) => {
                    console.log('override before:run');
                    await beforeRunHook(details);
                });

                on('after:run', async () => {
                    console.log('override after:run');
                    await afterRunHook();
                });
                on('task', verifyDownloadTasks);

                // Add the cypress-mochawesome-reporter plugin
                require('cypress-mochawesome-reporter/plugin')(on);

                // Make sure to return the config object as it might have been modified by the plugin.
                return config;
            },
        },

        component: {
            devServer: {
                framework: 'angular',
                bundler: 'webpack',
            },
            specPattern: '**/*.cy.ts',
        },
    })
);

e2e.ts 配置

// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

import '@applitools/eyes-cypress/commands';
import 'cypress-mochawesome-reporter/register';

// Import commands.js using ES2015 syntax:
import { SnackbarType } from '../../src/app/@shared/components/snackbar/model/snackbar.model';
import * as profile from '../e2e-mocked/signin/mocks/get.profile.json';
import * as settings from '../e2e-mocked/signin/mocks/get.settings.json';
import * as util from '../e2e-mocked/signin/mocks/get.util.json';
import { ApiMock } from '../interfaces/api-mock';
import './commands';

Cypress.on('uncaught:exception', () => {
    // returning false here prevents Cypress from
    // failing the test
    return false;
});

Cypress.Commands.add('login', (username: string, password: string) => {
    cy.request({
        method: 'POST',
        url: '/api/auth/signin',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            Cookie: 'XSRF-TOKEN=1',
            'X-XSRF-TOKEN': '1',
        },
        body: { username, password },
    });
});

Cypress.Commands.add('dismissModal', () => cy.get('.cdk-overlay-backdrop').click());
Cypress.Commands.add('clickAway', () => {
    cy.get('body').click();
});

Cypress.Commands.add('waitLoading', (state = 'not.exist') => cy.getBySelector('loading-spinner').should(`${state}`));
Cypress.Commands.add('waitSnackbar', (state = 'not.exist', type: SnackbarType = 'success') =>
    cy.get(`.sfc-snackbar.${type}`).should(`${state}`)
);
// support/commands.ts or support/index.ts

Cypress.Commands.add('waitUntilLoading', (timeout = 20000) => {
    cy.get('.mat-progress-spinner');
    cy.get('.mat-progress-spinner', { timeout }).should('not.exist', { failOnStatusCode: false });
});

Cypress.Commands.add('onMockedIntercept', ({ method, url, response, alias }: ApiMock<unknown>) => {
    if (Cypress.env('mock')) {
        cy.intercept(method, url, response).as(alias);
    }
});

Cypress.Commands.add('prepareMockTest', () => {
    cy.intercept('**/api/**', {
        statusCode: 404,
        log: false,
    }).as('mocked-but-not-intercepted');
    cy.intercept('**/api/auth/signin', {});
    cy.intercept('**/api/usermanagement/users/preferences', {
        enableAppNotifications: true,
        enableEmailNotifications: true,
    });
    cy.intercept('**/api/util', util);
    cy.intercept('**/api/users/profile', profile);
    cy.intercept('**/api/application_settings/get_mfa', {});
    cy.intercept('**/api/application_settings/settings', settings);
    cy.intercept('**/api/configuration/features/surveillance', { isEnabled: true });
    cy.intercept('**/api/configuration/features/supervision', { isEnabled: true });
    cy.intercept('**/api/notifications/unread-count', { unreadCount: 0 });
});

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('cy-verify-downloads').addCustomCommand();

declare global {
    // eslint-disable-next-line @typescript-eslint/no-namespace
    namespace Cypress {
        interface Chainable {
            login(username: string, password: string): Chainable<Response<unknown>>;

            waitUntilLoading(timeout?: number): Chainable<void>;

            dismissModal(): Chainable<JQuery<HTMLElement>>;

            clickAway(): Chainable<JQuery<HTMLElement>>;

            onMockedIntercept(mock: ApiMock<unknown>): Chainable<Response<unknown>>;

            verifyDownload(
                file: string,
                options?: {
                    contains?: true;
                    timeout?: number;
                    interval?: number;
                }
            ): Chainable<boolean>;

            waitLoading(state?: 'be.visible' | 'not.exist'): Chainable<JQuery<HTMLElement>>;

            waitSnackbar(state?: 'be.visible' | 'not.exist', type?: SnackbarType): Chainable<JQuery<HTMLElement>>;

            prepareMockTest(): void;
        }
    }
}
beforeEach(() => {
    const mockBackend = Cypress.env('mock');

    if (mockBackend) {
        cy.prepareMockTest();
    }
});

index.ts 配置

import 'cypress-mochawesome-reporter/cucumberSupport';

问题

测试执行正常,但未生成任何Mocha报告,求解决方法。


解决方案

1. 调整插件注册顺序

由于集成了@badeball/cypress-cucumber-preprocessor,报告器插件需要优先注册以确保兼容性。修改setupNodeEvents中的代码顺序:

async setupNodeEvents(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions): Promise<Cypress.PluginConfigOptions> {
    // 先注册报告器插件
    require('cypress-mochawesome-reporter/plugin')(on);
    
    // 再初始化Cucumber预处理器
    await addCucumberPreprocessorPlugin(on, config);
    on(
        'file:preprocessor',
        createBundler({
            plugins: [NodeModulesPolyfillPlugin(), createEsbuildPlugin(config)],
        })
    );
    
    on('task', verifyDownloadTasks);

    return config;
}

2. 修复报告目录配置

  • 检查reportDir的绝对路径是否存在,以及当前用户是否有读写权限。建议改用相对路径避免权限或路径错误:
    reporterOptions: {
        reportDir: 'cypress/reports',
        // 其他配置保持不变
    }
    
  • 手动创建cypress/reports目录,确保目录存在。

3. 移除冲突的钩子配置

你手动添加的before:run和after:run钩子会与cypress-mochawesome-reporter的默认钩子冲突,直接删除以下代码块:

on('before:run', async (details) => {
    console.log('override before:run');
    await beforeRunHook(details);
});

on('after:run', async () => {
    console.log('override after:run');
    await afterRunHook();
});

4. 统一Cucumber支持导入位置

将cypress-mochawesome-reporter/cucumberSupport直接导入到e2e.ts中,确保加载顺序正确:

// 在e2e.ts顶部添加
import 'cypress-mochawesome-reporter/cucumberSupport';

5. 确认测试运行方式

  • 使用命令行运行测试:npx cypress run,GUI模式下部分报告器功能可能受限。
  • 检查运行日志,查看是否有报告生成相关的错误提示。

6. 更新依赖版本

执行命令更新cypress-mochawesome-reporter到最新版本,确保与Cypress 13.x的兼容性:

npm update cypress-mochawesome-reporter --save-dev

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:29:51