最近,我正在寻找一种在GitHub Action中并行运行所有柏树测试的方法。我所有的测试都依次进行,花费太长了。
所以,这是我为解决这个问题所做的。
ð基本知识
默认情况下,所有作业在github动作中并行运行,除非您将need
语句放置并使一个作业取决于另一个作业。但是,如果您需要并行运行所有作业的任务,则需要使用GitHub Action的matrix
功能。
Matrix
允许您运行一组变量值,这些值的每种组合将导致并行运行的不同作业或步骤。
例如,
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
node-version: [10.x, 12.x, 14.x]
这将创建9个独立的作业,每个作业一个组合。 Github Action Docs中的更多信息。
为每个柏树测试创建并行作业
我们需要为柏树测试的每个规格创建一个矩阵,以便所有测试并行运行。在这里,每个规格代表一个文件中包含的所有测试。
1页创建一个JS文件以找到所有柏树规格。
此文件后来在.github/workflows
文件夹中使用。我在cypress/support
文件夹中创建了此文件。但是,您可以选择将其放在根或您喜欢的任何地方。
- 文件名:
locateCypressSpecsToRun.js
5
const fs = require('fs');
const path = require('path');
const getAllFiles = (dirPath, arrayOfFiles = []) => {
const files = fs.readdirSync(dirPath, { withFileTypes: true });
files.forEach((file) => {
if (file.isDirectory()) {
arrayOfFiles = getAllFiles(`${dirPath}/${file.name}`, arrayOfFiles);
} else {
arrayOfFiles.push(`${path.join(dirPath, '/', file.name)}`);
}
});
return arrayOfFiles;
};
const specs = getAllFiles('cypress/e2e');
process.stdout.write(`${JSON.stringify(specs)}\n`);
恳求注意:即使您在柏树中使用TypeScript,也不能在此处使用
.ts
文件扩展名,因为我们需要直接使用Node运行此文件。
-
在
getAllFiles()
内部,我将所有测试都位于位置的cypress/e2e
路径放置。根据需要对此进行修改。 -
如果您使用命令
node locateCypressSpecsToRun.js
运行此文件,则应该看到
//pretty version
specs = [
'cypress/e2e/test1.cy.ts',
'cypress/e2e/test2.cy.ts',
'cypress/e2e/test3.cy.ts',
'cypress/e2e/test4.cy.ts',
'cypress/e2e/test5.cy.ts',
];
2页建立矩阵
创建了规格位置的字符串后,是时候构建柏树矩阵了。柏树矩阵需要在yaml
文件中的作业内部。
jobs:
build-cypress-matrix:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v3
- id: set-matrix
run: echo "specs=$(node cypress/support/locateCypressSpecsToRun.js)" >> $GITHUB_OUTPUT
outputs:
specs: ${{ steps.set-matrix.outputs.specs }}
-
解释:
run
和specs
-
run: echo "specs=$(node cypress/support/locateCypressSpecsToRun.js)" >> $GITHUB_OUTPUT
:此行使用运行键指定要运行的shell命令。在这种情况下,该命令为
echo
,然后是一个在cypress/support/locateCypressSpecsToRun.js
中运行node.js脚本的字符串。脚本的输出是通过用$()
围绕命令捕获的,并存储在称为Specs的外壳变量中。>>
操作员将命令的输出附加到一个名为$GITHUB_OUTPUT
的文件,该文件是github操作中的预定义环境变量,可捕获步骤的输出。
您可以阅读有关$GITHUB_OUTPUT
here的更多信息。 -
outputs
:specs: ${{ steps.set-matrix.outputs.specs }}
此行使用输出密钥来定义称为Set-Matrix的步骤的输出。输出称为规格,其值设置为使用
${{ steps.set-matrix.outputs.specs }}
语法在运行命令中设置的规格变量的值。这允许工作流中的后续步骤访问规格变量的值。
为了简化,我们正在分配specs: specs
。
-
3页要制作其他工作所需的矩阵。
确保在运行测试之前完成build-cypress-matrix
作业。因此,使用Action的needs
语句。例如,您可以做这样的事情。
regression:
needs: [notify-slack-on-start, build-cypress-matrix]
# rest of the code ......
在这种情况下,还需要notify-slack-on-start
运行regression
Job
4页定义矩阵
在您想要并行运行的作业中,添加预先构建的柏树测试矩阵。请参阅最后的specs:
线。
regression:
needs: [notify-slack-on-start, build-cypress-matrix]
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 64
matrix:
config:
[
{
type: 'desktop',
config: 'viewportWidth=1920,viewportHeight=1080',
},
]
browser: [chrome, firefox, edge, safari]
specs: ${{ fromJson(needs.build-cypress-matrix.outputs.specs) }}
-
在这种情况下,我定义了三个矩阵。
-
browser
:我想要测试的所有浏览器 - 一个适合
config
:浏览器的大小 -
最后
specs
:-
fromJson
:此功能将JSON字符串转换为对象,请阅读有关此GitHub Action函数here的更多信息。它用于将输出从build-cypress-matrix
作业转换为对象。 -
needs
:此功能用于表明当前作业取决于另一个作业的输出。在这种情况下,它用于表明回归作业需要build-cypress-matrix
作业的输出。
因此,
${{fromJson(needs.build-cypress-matrix.outputs.specs).specs}}
首先使用needs
获取build-cypress-matrix
作业的输出。然后,fromJson
函数将此输出从JSON字符串转换为对象,该对象具有称为specs
的属性,该属性包含要运行的Cypress Spec文件列表。最后,从对象中提取specs
属性,并用作matrix
作业中specs
字段的值。 -
-
5接£使用矩阵
最后,像浏览器或操作系统一样使用规格矩阵。
- name: My Awesome Cypress Tests
uses: cypress-io/github-action@v5
with:
browser: ${{ matrix.browser }}
config: ${{ matrix.config.config }}
spec: ${{ matrix.specs }}
ð€示例
这是一个完整的工作流程。
# sample document.
name: Testing Parallel Runs
on:
workflow_dispatch:
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL_CYPRESS }}
SLACK_ICON: https://github.githubassets.com/images/modules/site/features/actions-icon-actions.svg
SLACK_CHANNEL: cypress-notifications
jobs:
notify-slack-on-start:
runs-on: ubuntu-latest
steps:
- uses: rtCamp/action-slack-notify@v2.0.2
name: notify slack on run start
env:
SLACK_TITLE: My Awesome Cypress Tests
SLACK_COLOR: good
SLACK_MESSAGE: 'Automation has started :white_check_mark:'
build-cypress-matrix:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v3
- id: set-matrix
run: echo "specs=$(node cypress/support/locateCypressSpecsToRun.js)" >> $GITHUB_OUTPUT
outputs:
specs: ${{ steps.set-matrix.outputs.specs }}
regression:
needs: [notify-slack-on-start, build-cypress-matrix]
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 64
matrix:
config:
[
{
type: 'desktop',
config: 'viewportWidth=1920,viewportHeight=1080',
},
]
browser: [chrome]
specs: ${{ fromJson(needs.build-cypress-matrix.outputs.specs) }}
env:
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
CYPRESS_PASSWORD: ${{secrets.CYPRESS_PASSWORD}}
CYPRESS_configFile: prod
# add other env as necessary
steps:
- name: Checkout
uses: actions/checkout@v3
- name: copy npmtoken to npmrc
run: cp .npmtoken .npmrc
# this step is only necessary if you are using private npm packages and need to provide .npmrc to github runner.
- name: My Awesome Cypress Tests
uses: cypress-io/github-action@v5
with:
browser: ${{ matrix.browser }}
config: ${{ matrix.config.config }}
spec: ${{ matrix.specs }}
- name: Generate report
if: failure()
uses: actions/upload-artifact@v2
with:
name: Failed on ${{matrix.browser}}-${{matrix.config.type}}
path: |
cypress/report/*
cypress/screenshots/*
cypress/videos/*
- uses: rtCamp/action-slack-notify@v2.0.2
name: notify slack on failure
if: failure()
env:
SLACK_TITLE: Test(s) failed while running on ${{matrix.config.type}}
SLACK_COLOR: danger
SLACK_MESSAGE: ':failed: :computer-rage: Automation Failure on Prod! <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>'
notify-slack-on-completion:
needs: regression
runs-on: ubuntu-latest
steps:
- uses: rtCamp/action-slack-notify@v2.0.2
name: notify slack on run completion
env:
SLACK_TITLE: My Awesome Cypress Tests
SLACK_COLOR: good
SLACK_MESSAGE: ':pass: :white_check_mark: Automation Successful on Prod! <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>'
ð结论
最后,我想分享这种模式可用于木偶,嘲笑和其他框架。这种方法的主要好处是,如果付费墙落后,您就不必为并行运行能力付费。另外,它有助于减少您需要等待所有工作完成的时间。