460b203b38
## What
Adds a custom Jest reporter to **twenty-front** that, in CI, suppresses
passing-test output and surfaces only failures — mirroring what we
already do for **twenty-server**.
## How
- New `packages/twenty-front/jest-failures-only-reporter.cjs` — a
verbatim port of
`packages/twenty-server/jest-failures-only-reporter.js`. It prints a
`FAIL` block per failing suite plus a final "FAILED TEST SUITES
SUMMARY", and otherwise emits only the suite/test totals.
- Wired into `packages/twenty-front/jest.config.mjs` via `...(isCI && {
reporters: ['./jest-failures-only-reporter.cjs'] })`, gated on `CI ===
'true'` exactly like twenty-server.
### Note on the `.cjs` extension
twenty-front's `package.json` sets `"type": "module"`, so a `.js`
reporter is parsed as ESM and `module.exports` throws. Renaming to
`.cjs` keeps the file as CommonJS (Jest requires CJS reporters).
twenty-server is not an ESM package, hence its `.js` extension.
## Testing
- Passing suite (`CI=true npx jest <file>`): output reduced to the
totals summary only.
- Temporary failing suite: shows the `FAIL` block, failure message, and
the failed-suites summary.
Local dev runs (no `CI` env) are unaffected — the default reporter is
used.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22345?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
89 lines
2.3 KiB
JavaScript
89 lines
2.3 KiB
JavaScript
class JestFailuresOnlyReporter {
|
|
constructor() {
|
|
this._failures = [];
|
|
}
|
|
|
|
onTestResult(_test, testResult) {
|
|
if (testResult.numFailingTests === 0 && !testResult.testExecError) {
|
|
return;
|
|
}
|
|
|
|
const relativePath = testResult.testFilePath.replace(
|
|
process.cwd() + '/',
|
|
'',
|
|
);
|
|
|
|
process.stderr.write(`\n\x1b[31mFAIL\x1b[0m ${relativePath}\n`);
|
|
|
|
if (testResult.failureMessage) {
|
|
process.stderr.write(testResult.failureMessage + '\n');
|
|
}
|
|
|
|
if (testResult.testExecError) {
|
|
process.stderr.write(
|
|
`\n Runtime error: ${testResult.testExecError.message}\n`,
|
|
);
|
|
}
|
|
|
|
this._failures.push({ path: relativePath, testResult });
|
|
}
|
|
|
|
onRunComplete(_testContexts, aggregatedResults) {
|
|
const {
|
|
numPassedTestSuites,
|
|
numFailedTestSuites,
|
|
numTotalTestSuites,
|
|
numPassedTests,
|
|
numFailedTests,
|
|
numTotalTests,
|
|
} = aggregatedResults;
|
|
|
|
process.stderr.write('\n');
|
|
|
|
if (this._failures.length > 0) {
|
|
process.stderr.write(
|
|
`\x1b[31m${'='.repeat(60)}\x1b[0m\n` +
|
|
`\x1b[31m FAILED TEST SUITES SUMMARY\x1b[0m\n` +
|
|
`\x1b[31m${'='.repeat(60)}\x1b[0m\n\n`,
|
|
);
|
|
|
|
for (const failure of this._failures) {
|
|
process.stderr.write(` \x1b[31m✕\x1b[0m ${failure.path}\n`);
|
|
|
|
const failedTests = failure.testResult.testResults.filter(
|
|
(result) => result.status === 'failed',
|
|
);
|
|
|
|
for (const failedTest of failedTests) {
|
|
process.stderr.write(` \x1b[31m→\x1b[0m ${failedTest.fullName}\n`);
|
|
}
|
|
|
|
process.stderr.write('\n');
|
|
}
|
|
|
|
process.stderr.write(`\x1b[31m${'='.repeat(60)}\x1b[0m\n\n`);
|
|
}
|
|
|
|
const suiteSummary =
|
|
`Test Suites: ` +
|
|
(numFailedTestSuites > 0
|
|
? `\x1b[31m${numFailedTestSuites} failed\x1b[0m, `
|
|
: '') +
|
|
(numPassedTestSuites > 0
|
|
? `\x1b[32m${numPassedTestSuites} passed\x1b[0m, `
|
|
: '') +
|
|
`${numTotalTestSuites} total`;
|
|
|
|
const testSummary =
|
|
`Tests: ` +
|
|
(numFailedTests > 0 ? `\x1b[31m${numFailedTests} failed\x1b[0m, ` : '') +
|
|
(numPassedTests > 0 ? `\x1b[32m${numPassedTests} passed\x1b[0m, ` : '') +
|
|
`${numTotalTests} total`;
|
|
|
|
process.stderr.write(suiteSummary + '\n');
|
|
process.stderr.write(testSummary + '\n');
|
|
}
|
|
}
|
|
|
|
module.exports = JestFailuresOnlyReporter;
|