如何在使用 Cypress 运行第一次测试之前运行命令

Zet*_*eth -2 cypress

我想在第一次测试之前执行一个设置夹具的命令。但它不应该在每次测试之前运行 - 就在第一个测试之前运行。

我正在尝试获取已部署应用程序的功能标志,我正在对其进行测试(本地、暂存或生产)。在应用程序中,功能标志存储在window对象上:window.featureFlags。我的setupFixtures函数应该将这些功能标志保存到我的fixtures/feature-flags.json. 这样,我将能够根据部署的代码查看是否启用了某个功能。

然后我可以将其添加到我的所有测试中:

beforeEach( function(){
  if( !isFeatureEnabled( 'FEATURENAME' ) ){
    this.skip();
  }
});
Run Code Online (Sandbox Code Playgroud)

这意味着它将从给定的部署代码中获取 featureName。如果未启用 featureName,则会自动跳过该测试。

  • 如果我运行一个名为 的测试test-header.cy.ts,那么我希望我的测试能够执行以下操作:

    • 获取功能标志并将其保存到fixtures/feature-flags.json
    • 运行test-header.cy.ts测试
  • 如果我有三个测试:test-x.cy.tstest-y.cy.tstest-z.cy.ts,那么我希望它这样做:

    • 获取功能标志并将其保存到fixtures/feature-flags.json
    • 运行test-x.cy.ts测试
    • 运行test-y.cy.ts测试
    • 运行test-z.cy.ts测试

我该怎么做呢?

我试过了:

  1. 将一部分添加before到我的e2e.ts文件中:

    这需要定义一些辅助函数和任务,但如果我这样做:

    // Add isFeaturedEnabled globally (so we don't need to import it every time)
    function isFeatureEnabled(featureName) {
      if (!globalThis.featureFlags) {
        throw new Error('Feature flags are not set');
      }
    
      const feature = globalThis.featureFlags.find((feature) => feature.name === featureName);
      return Boolean(feature && feature.enabled);
    }
    
    globalThis.isFeatureEnabled = isFeatureEnabled; // Attach the function to the global scope
    // END OF: Add isFeaturedEnabled globally
    
    before(() => {
      const filePath = 'cypress/fixtures/tmp/featureFlags.json';
    
      // Reset featureFlags, to ensure to get the latest one
      cy.task('fileExists', filePath)
        .then((exists) => {
          if (exists) {
            cy.exec(`rm ${filePath}`);
          }
        })
        .then(() => {
          cy.visit('/');
          cy.window().then((win) => {
            if (win.featureFlags && win.featureFlags.length > 0) {
              cy.writeFile(filePath, win.featureFlags);
              globalThis.featureFlags = win.featureFlags;
            } else {
              cy.writeFile(filePath, []);
              globalThis.featureFlags = [];
            }
          });
        });
    });
    
    Run Code Online (Sandbox Code Playgroud)

    这是有效的。但这意味着它cypress/fixtures/tmp/featureFlags.json在每次单独测试之前都会生成一个新的,这浪费了相当多的时间。特别是因为它每次都需要重新加载主页(以便可以访问窗口对象)。

  2. 制作一个“设置测试”bash 脚本或其他东西

    我可以制作一个小脚本,在运行测试之前设置功能标志固定装置。这也是一个不错的选择,但它也会增加我的同事在不同的环境中运行时忘记重新运行该选项的可能性,从而给他们带来误报。

小智 5

如果您只想针对运行中的所有规范运行代码一次,则应使用Before Run API而不是before()挂钩。

由于它运行在 Node 进程中,因此使用 fs.unlink 来删除该文件。

文档中的示例:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  // setupNodeEvents can be defined in either
  // the e2e or component configuration
  e2e: {
    setupNodeEvents(on, config) {
      on('before:run', (details) => {
        /* code that needs to run before all specs */
      })
    },
    experimentalInteractiveRunEvents: true,   // use for cypress open mode
  },
})
Run Code Online (Sandbox Code Playgroud)

但是,您的代码看起来非常不必要,我会在每次访问时win.features将该属性读入环境变量中。

参见Cypress.env

范围

使用 Cypress.env 设置的环境变量仅在当前规范文件的范围内。

Cypress 独立运行每个规范文件:浏览器在规范之间退出。

cy.visit('http://localhost:3000/#/users', {
  onLoad: (win) => {
    const flags = win.featureFlags || []  // default to empty
    Cypress.env('flags', flags)
  },
})
Run Code Online (Sandbox Code Playgroud)

Cypress.env()避免因测试清理造成的全局污染和意外Bug。您当前的方法不太可能在测试隔离最佳实践中幸存下来。