Compare commits

...

5 Commits

Author SHA1 Message Date
Ryan Laurie
956d06348d kick ci 2025-03-13 11:54:36 -06:00
Ryan Laurie
ded9809371 kick ci 2025-03-13 11:54:21 -06:00
Ryan Laurie
2f090b6c82 kick ci 2025-03-13 11:54:09 -06:00
Ryan Laurie
afdf6596da kick ci 2025-03-13 11:54:04 -06:00
Filip Hric
14334b548b run only previously failed tests when rerunning pipeline 2025-03-13 10:32:46 +01:00
4 changed files with 179 additions and 1 deletions

90
.github/scripts/process-failed-tests.js vendored Normal file
View File

@@ -0,0 +1,90 @@
const fs = require('fs');
const path = require('path');
function processFailedTests() {
const failedTestsDir = 'failed-tests';
const testGroup = process.env.TEST_GROUP;
console.log('Current working directory:', process.cwd());
if (!fs.existsSync(failedTestsDir)) {
console.log(`No failed test results found for ${testGroup}`);
return;
}
// Log directory structure
console.log('Directory structure of failed-tests:');
function logDir(dir, prefix = '') {
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
console.log(`${prefix}${item.name}${item.isDirectory() ? '/' : ''}`);
if (item.isDirectory()) {
logDir(path.join(dir, item.name), prefix + ' ');
}
}
}
logDir(failedTestsDir);
console.log(`Found failed test results for ${testGroup}:`);
const specs = new Set();
// Read all files in the directory recursively
function processDirectory(dir) {
const files = fs.readdirSync(dir, { withFileTypes: true });
for (const file of files) {
const fullPath = path.join(dir, file.name);
if (file.isDirectory()) {
processDirectory(fullPath);
continue;
}
console.log(`Processing ${fullPath}`);
try {
const content = fs.readFileSync(fullPath, 'utf8');
const results = JSON.parse(content);
// Handle both JSON structures
if (Array.isArray(results)) {
// Handle array structure: [{"spec": "path/to/spec.cy.spec.ts", ...}]
results.forEach(result => {
if (result.spec) {
specs.add(result.spec);
console.log(`Found spec: ${result.spec}`);
}
});
} else if (results.results?.[0]?.file) {
// Handle object structure: { results: [{ file: "path/to/spec.cy.spec.ts" }] }
const specPath = results.results[0].file;
specs.add(specPath);
console.log(`Found spec: ${specPath}`);
} else {
console.log(`No valid spec path in ${fullPath}. JSON structure:`, JSON.stringify(results, null, 2));
}
} catch (error) {
if (error instanceof SyntaxError) {
console.log(`Invalid JSON in ${fullPath}`);
} else {
console.log(`Error processing ${fullPath}: ${error.message}`);
}
}
}
}
processDirectory(failedTestsDir);
const specsList = Array.from(specs);
if (specsList.length > 0) {
console.log(`Found failed specs for ${testGroup}: ${specsList.join(',')}`);
// Set output for GitHub Actions
const output = process.env.GITHUB_OUTPUT;
if (output) {
fs.appendFileSync(output, `specs=${specsList.join(',')}\n`);
}
} else {
console.log(`No valid spec paths found in results for ${testGroup}`);
}
}
processFailedTests();

View File

@@ -98,6 +98,19 @@ jobs:
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Download failed test artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
pattern: failed-tests-${{ inputs.name }}-${{ inputs.edition }}
path: failed-tests
- name: Process failed tests
id: process-failed-tests
env:
TEST_GROUP: ${{ inputs.name }}-${{ inputs.edition }}
run: node .github/scripts/process-failed-tests.js
- name: Run Snowplow micro
uses: ./.github/actions/run-snowplow-micro
@@ -119,17 +132,22 @@ jobs:
SPLIT_SUMMARY: false
shell: bash
run: |
SPEC_PATH="${{ steps.process-failed-tests.outputs.specs || inputs.specs }}"
echo "Running tests with specs: $SPEC_PATH"
node e2e/runner/run_cypress_ci.js e2e \
--env grepTags="-@mongo+-@flaky+-@OSS --@quarantine",grepOmitFiltered=true \
--spec "$SPEC_PATH" \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
- name: Run Tagged EE Cypress tests on ${{ inputs.name }}
if: ${{ inputs.specs }}
shell: bash
run: |
SPEC_PATH="${{ steps.process-failed-tests.outputs.specs || inputs.specs }}"
echo "Running tests with specs: $SPEC_PATH"
node e2e/runner/run_cypress_ci.js e2e \
--env grepTags="${{inputs.tags}} --@quarantine",grepOmitFiltered=true \
--spec '${{ inputs.specs }}' \
--spec "$SPEC_PATH" \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
- name: Upload Test Results
@@ -154,6 +172,13 @@ jobs:
./logs/test.log
if-no-files-found: ignore
- name: Upload Failed Tests
uses: actions/upload-artifact@v4
if: failure()
with:
name: failed-tests-${{ inputs.name }}-${{ inputs.edition }}
path: ./cypress/test-results
- name: Publish Summary
if: failure()
uses: actions/github-script@v7

View File

@@ -0,0 +1,60 @@
const fs = require("fs");
const path = require("path");
/**
* Collects failed tests from the most recent Cypress test run
*
* After each run, a file will store failed test titles within a test-results directory
*
* The test-results directory will be stored in the cypress.config directory
*
* Subsequent test runs containing failed tests will overwrite this file
* @param {*} on
* @param {*} config
* @returns
*/
const collectFailingTests = (on, config) => {
on("after:run", async results => {
let failedTests = [];
for (const run of results.runs) {
if (run.tests && run.spec) {
const tests = run.tests
.filter(test => test.state === "failed")
.map(test => test.title);
const spec = run.spec.relative;
failedTests = failedTests.concat(generateReports(tests, spec));
}
}
const failedTestFilePath = "../../cypress/test-results/";
// Create the directory and last-run file where failed tests will be written to
await fs.promises.mkdir(failedTestFilePath, { recursive: true });
const lastRunReportFile = path.join(failedTestFilePath, "last-run.json");
await fs.promises.writeFile(lastRunReportFile, JSON.stringify(failedTests));
});
return collectFailingTests;
};
const generateReports = (tests, spec) => {
const reports = [];
for (const test of tests) {
const testCopy = [...test]; // Create a copy of the array to avoid mutation
const testTitle = testCopy.pop(); // Extract the test title
if (testTitle) {
const report = {
spec: spec,
parent: testCopy, // Parent titles
test: testTitle, // The actual test title
};
reports.push(report);
}
}
return reports;
};
export { collectFailingTests };

View File

@@ -4,6 +4,7 @@ import path from "node:path";
import installLogsPrinter from "cypress-terminal-report/src/installLogsPrinter";
import * as ciTasks from "./ci_tasks";
import { collectFailingTests } from "./collectFailedTests";
import {
removeDirectory,
verifyDownloadTasks,
@@ -160,6 +161,8 @@ const defaultConfig = {
}
});
collectFailingTests(on, config);
return config;
},
supportFile: "e2e/support/cypress.js",