Files
overleaf-cep/libraries/eslint-plugin/no-mocha-before.js
T
Jakob Ackermann 5425202247 [e2e] cut down flakeyness (#35896)
* [saas-e2e] conversion: wait for initial compile before looking at PDF

* [eslint-plugin] s/before/beforeWithReRunOnTestRetry/ in e2e tests

* [server-ce] remove filestore migration scripts and E2E tests

* [server-ce] test: trim down upgrading tests to 5.x -> latest

GitOrigin-RevId: 2426ec4a4f3d67a5e0e7850ea84a942ae4619f94
2026-09-17 11:38:44 +00:00

113 lines
3.6 KiB
JavaScript

const Path = require('node:path')
/**
* Block bare mocha `before()` hooks in Cypress e2e suites.
*
* `before()` hooks run once per suite and do NOT re-run when a test retries,
* while `beforeEach`-based hooks (like `beforeWithReRunOnTestRetry`) do.
* Mixing the two also changes ordering: all `before()` hooks run ahead of
* every `beforeEach`, not in source order. This matters in the Server Pro
* e2e suite, where suites change the server config via `startWith()` while
* test setup runs in `beforeWithReRunOnTestRetry()`: when a later suite
* changes the config, both must re-run on retry and in registration order,
* otherwise a retried test runs against setup or config belonging to a
* different suite.
*
* The autofix rewrites `before(fn)` to `beforeWithReRunOnTestRetry(fn)` and
* adds the helper import when missing. Configure the helper location (repo
* root relative, no extension) via the `helperPath` option.
*/
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'Disallow mocha before() hooks in favor of beforeWithReRunOnTestRetry()',
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
helperPath: { type: 'string' },
},
additionalProperties: false,
},
],
messages: {
noMochaBefore:
'before() hooks do not re-run when a test retries, so retried tests run against stale setup. Use beforeWithReRunOnTestRetry() instead.',
},
},
create(context) {
const helperPath = context.options[0]?.helperPath
let lastImport = null
let hasHelperImport = false
function helperImportSpecifier() {
const absolute = Path.resolve(context.cwd, helperPath)
let relative = Path.relative(
Path.dirname(Path.resolve(context.cwd, context.filename)),
absolute
)
relative = relative.split(Path.sep).join('/')
if (!relative.startsWith('.')) {
relative = `./${relative}`
}
return relative
}
return {
ImportDeclaration(node) {
lastImport = node
if (
node.specifiers.some(
specifier =>
specifier.type === 'ImportSpecifier' &&
specifier.imported.name === 'beforeWithReRunOnTestRetry'
)
) {
hasHelperImport = true
}
},
CallExpression(node) {
if (
node.callee.type !== 'Identifier' ||
node.callee.name !== 'before'
) {
return
}
// Only the global mocha hook; skip locally defined/imported `before`
const variable = context.sourceCode
.getScope(node)
.references.find(ref => ref.identifier === node.callee)?.resolved
if (variable && variable.defs.length > 0) {
return
}
const fixable = node.arguments.length === 1 && helperPath
context.report({
node: node.callee,
messageId: 'noMochaBefore',
fix: fixable
? fixer => {
const fixes = [
fixer.replaceText(node.callee, 'beforeWithReRunOnTestRetry'),
]
if (!hasHelperImport) {
const importText = `import { beforeWithReRunOnTestRetry } from '${helperImportSpecifier()}'`
fixes.push(
lastImport
? fixer.insertTextAfter(lastImport, `\n${importText}`)
: fixer.insertTextBeforeRange([0, 0], `${importText}\n`)
)
}
return fixes
}
: undefined,
})
},
}
},
}