mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-13 21:53:43 +01:00
[saas-e2e] initial revision of SaaS E2E tests running in the dev-env (#24311)
* [saas-e2e] initial revision of SaaS E2E tests running in the dev-env * [v1] make rubocop happy * [v1] make rubocop happy * [saas-e2e] more retries for webpack startup check Co-authored-by: Alf Eaton <alf.eaton@overleaf.com> * [web] restrict e2e_test_setup.mjs to running in the dev-env Co-authored-by: Mathias Jakobsen <mathias.jakobsen@overleaf.com> * [saas-e2e] import latest split-tests from production --------- Co-authored-by: Alf Eaton <alf.eaton@overleaf.com> Co-authored-by: Mathias Jakobsen <mathias.jakobsen@overleaf.com> GitOrigin-RevId: 034343ee56b8d059090d8a5de74eaac24429b527
This commit is contained in:
committed by
Copybot
co-authored by
Alf Eaton
Mathias Jakobsen
parent
13bf214a3c
commit
7b69d61540
@@ -0,0 +1,169 @@
|
||||
import fs from 'node:fs'
|
||||
import Path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { promiseMapWithLimit } from '@overleaf/promise-utils'
|
||||
import Settings from '@overleaf/settings'
|
||||
import { db } from '../app/src/infrastructure/mongodb.js'
|
||||
import GracefulShutdown from '../app/src/infrastructure/GracefulShutdown.js'
|
||||
import ProjectDeleter from '../app/src/Features/Project/ProjectDeleter.js'
|
||||
import SplitTestManager from '../app/src/Features/SplitTests/SplitTestManager.js'
|
||||
import UserDeleter from '../app/src/Features/User/UserDeleter.js'
|
||||
import UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.js'
|
||||
|
||||
const MONOREPO = Path.dirname(
|
||||
Path.dirname(Path.dirname(Path.dirname(fileURLToPath(import.meta.url))))
|
||||
)
|
||||
|
||||
/**
|
||||
* @param {string} email
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function createUser(email) {
|
||||
const user = await UserRegistrationHandler.promises.registerNewUser({
|
||||
email,
|
||||
password: process.env.CYPRESS_DEFAULT_PASSWORD,
|
||||
})
|
||||
const features = email.startsWith('free@')
|
||||
? Settings.defaultFeatures
|
||||
: Settings.features.professional
|
||||
await db.users.updateOne(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
// Set admin flag.
|
||||
isAdmin: email.startsWith('admin@'),
|
||||
// Disable spell-checking for performance and flakiness reasons.
|
||||
'ace.spellCheckLanguage': '',
|
||||
// Override features.
|
||||
features,
|
||||
featuresOverrides: [{ features }],
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} email
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function deleteUser(email) {
|
||||
const user = await db.users.findOne({ email })
|
||||
if (!user) return
|
||||
// Soft delete the user.
|
||||
await UserDeleter.promises.deleteUser(user._id, {
|
||||
force: true,
|
||||
ipAddress: '0.0.0.0',
|
||||
})
|
||||
// Hard-delete the users projects.
|
||||
const projects = await db.deletedProjects
|
||||
.find(
|
||||
{ deletedProjectOwnerId: user._id },
|
||||
{ projection: { deletedProjectId: 1 } }
|
||||
)
|
||||
.toArray()
|
||||
await promiseMapWithLimit(
|
||||
10,
|
||||
projects.map(p => p.deletedProjectId),
|
||||
ProjectDeleter.promises.expireDeletedProject
|
||||
)
|
||||
// Hard-delete the user.
|
||||
await UserDeleter.promises.expireDeletedUser(user._id)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} email
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function provisionUser(email) {
|
||||
await deleteUser(email)
|
||||
await createUser(email)
|
||||
}
|
||||
|
||||
async function provisionUsers() {
|
||||
const emails = Settings.recaptcha.trustedUsers
|
||||
console.log(`> Provisioning ${emails.length} E2E users.`)
|
||||
await promiseMapWithLimit(3, emails, provisionUser)
|
||||
}
|
||||
|
||||
async function purgeNewUsers() {
|
||||
const users = await db.users
|
||||
.find(
|
||||
{ email: Settings.recaptcha.trustedUsersRegex },
|
||||
{ projection: { email: 1 } }
|
||||
)
|
||||
.toArray()
|
||||
console.log(`> Deleting ${users.length} newly created E2E users.`)
|
||||
await promiseMapWithLimit(
|
||||
3,
|
||||
users.map(user => user.email),
|
||||
deleteUser
|
||||
)
|
||||
}
|
||||
|
||||
const SPLIT_TEST_OVERRIDES = [
|
||||
// disable writefull, oauth registration does not work in dev-env and their banners hide our buttons.
|
||||
{
|
||||
name: 'writefull-auto-account-creation',
|
||||
versions: [
|
||||
{
|
||||
versionNumber: 1,
|
||||
phase: 'release',
|
||||
active: true,
|
||||
analyticsEnabled: false,
|
||||
variants: [{ name: 'enabled', rolloutPercent: 0, rolloutStripes: [] }],
|
||||
createdAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
async function provisionSplitTests() {
|
||||
const backup = Path.join(
|
||||
MONOREPO,
|
||||
'backup',
|
||||
'split-tests',
|
||||
new Date().toISOString() + '.json'
|
||||
)
|
||||
console.log(
|
||||
`> Backing up previous split-tests into ${backup}. You can import them again on https://www.dev-overleaf.com/admin/split-test via the [Import] button.`
|
||||
)
|
||||
const splitTests = await SplitTestManager.getRuntimeTests()
|
||||
await fs.promises.mkdir(Path.dirname(backup), { recursive: true })
|
||||
await fs.promises.writeFile(
|
||||
backup,
|
||||
JSON.stringify(splitTests.sort((a, b) => (a.name > b.name ? 1 : -1)))
|
||||
)
|
||||
|
||||
// Imported from production via https://www.overleaf.com/admin/split-test -> "Copy all split tests" -> "Copy for E2E test setup"
|
||||
const SPLIT_TESTS = JSON.parse(
|
||||
await fs.promises.readFile(
|
||||
Path.join(MONOREPO, 'tools/saas-e2e/split-tests.json')
|
||||
)
|
||||
)
|
||||
console.log(`> Importing ${SPLIT_TESTS.length} split-tests from production.`)
|
||||
await SplitTestManager.replaceSplitTests(SPLIT_TESTS)
|
||||
console.log(
|
||||
`> Importing ${SPLIT_TEST_OVERRIDES.length} split-tests for test compatibility.`
|
||||
)
|
||||
await SplitTestManager.mergeSplitTests(SPLIT_TEST_OVERRIDES, true)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
throw new Error('only available in dev-env')
|
||||
}
|
||||
|
||||
await purgeNewUsers()
|
||||
await provisionUsers()
|
||||
await provisionSplitTests()
|
||||
}
|
||||
|
||||
await main()
|
||||
await GracefulShutdown.gracefulShutdown(
|
||||
{
|
||||
close(cb) {
|
||||
cb()
|
||||
},
|
||||
},
|
||||
'SIGTERM'
|
||||
)
|
||||
Reference in New Issue
Block a user