[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
This commit is contained in:
Jakob Ackermann
2026-09-17 11:38:44 +00:00
committed by Copybot
parent 1b519d59a5
commit 5425202247
7 changed files with 192 additions and 4199 deletions
+1
View File
@@ -22,5 +22,6 @@ module.exports = {
'sorted-keys-in-locales': require('./sorted-keys-in-locales'),
'locale-variables-match-en': require('./locale-variables-match-en'),
'no-orphan-locale-keys': require('./no-orphan-locale-keys'),
'no-mocha-before': require('./no-mocha-before'),
},
}
+112
View File
@@ -0,0 +1,112 @@
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,
})
},
}
},
}
@@ -14,6 +14,7 @@ import noConsecutiveSpacesInLocales from '../../no-consecutive-spaces-in-locales
import noStraightApostrophesInLocales from '../../no-straight-apostrophes-in-locales.js'
import frenchTypographyInLocales from '../../french-typography-in-locales.js'
import sortedKeysInLocales from '../../sorted-keys-in-locales.js'
import noMochaBefore from '../../no-mocha-before.js'
const __filename = fileURLToPath(import.meta.url)
@@ -546,3 +547,81 @@ jsonRuleTester.run('french-typography-in-locales', frenchTypographyInLocales, {
},
],
})
const noMochaBeforeOptions = [
{ helperPath: 'server-ce/test/helpers/beforeWithReRunOnTestRetry' },
]
ruleTester.run('no-mocha-before', noMochaBefore, {
valid: [
{
code: `beforeEach(function () { setup() })`,
options: noMochaBeforeOptions,
},
{
code: `import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
beforeWithReRunOnTestRetry(function () { setup() })`,
options: noMochaBeforeOptions,
},
{
// locally defined `before` is not the mocha hook
code: `function before(fn) { fn() }
before(function () { setup() })`,
options: noMochaBeforeOptions,
},
],
invalid: [
{
// rename + import added after the last existing import
filename: 'server-ce/test/foo.spec.ts',
code: `import { login } from './helpers/login'
before(async function () { this.timeout(1000) })`,
options: noMochaBeforeOptions,
errors: 1,
output: `import { login } from './helpers/login'
import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
beforeWithReRunOnTestRetry(async function () { this.timeout(1000) })`,
},
{
// no imports yet: import inserted at the top
filename: 'server-ce/test/foo.spec.ts',
code: `before(function () { setup() })`,
options: noMochaBeforeOptions,
errors: 1,
output: `import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
beforeWithReRunOnTestRetry(function () { setup() })`,
},
{
// helper already imported: rename only
filename: 'server-ce/test/foo.spec.ts',
code: `import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
before(function () { setup() })`,
options: noMochaBeforeOptions,
errors: 1,
output: `import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
beforeWithReRunOnTestRetry(function () { setup() })`,
},
{
// file inside helpers/: relative path has no directory prefix
filename: 'server-ce/test/helpers/config.ts',
code: `before(function () { setup() })`,
options: noMochaBeforeOptions,
errors: 1,
output: `import { beforeWithReRunOnTestRetry } from './beforeWithReRunOnTestRetry'
beforeWithReRunOnTestRetry(function () { setup() })`,
},
{
// two-argument mocha form: report without autofix
filename: 'server-ce/test/foo.spec.ts',
code: `before('named hook', function () { setup() })`,
options: noMochaBeforeOptions,
errors: 1,
},
{
// no helperPath configured: report without autofix
filename: 'server-ce/test/foo.spec.ts',
code: `before(function () { setup() })`,
errors: 1,
},
],
})