[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:
Jakob Ackermann
2025-03-18 10:56:36 +00:00
committed by Copybot
parent 13bf214a3c
commit 7b69d61540
5 changed files with 492 additions and 6 deletions

317
package-lock.json generated
View File

@@ -30,7 +30,8 @@
"services/third-party-datastore",
"services/third-party-references",
"services/tpdsworker",
"services/web"
"services/web",
"tools/saas-e2e"
],
"dependencies": {
"patch-package": "^8.0.0"
@@ -6441,6 +6442,29 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/@isomorphic-git/idb-keyval": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@isomorphic-git/idb-keyval/-/idb-keyval-3.3.2.tgz",
"integrity": "sha512-r8/AdpiS0/WJCNR/t/gsgL+M8NMVj/ek7s60uz3LmpCaTF2mEVlZJlB01ZzalgYzRLXwSPC92o+pdzjM7PN/pA==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/@isomorphic-git/lightning-fs": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@isomorphic-git/lightning-fs/-/lightning-fs-4.6.0.tgz",
"integrity": "sha512-tfon8f1h6LawjFI/d8lZPWRPTxmdvyTMbkT/j5yo6dB0hALhKw5D9JsdCcUu/D1pAcMMiU7GZFDsDGqylerr7g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@isomorphic-git/idb-keyval": "3.3.2",
"isomorphic-textencoder": "1.0.1",
"just-debounce-it": "1.1.0",
"just-once": "1.1.0"
},
"bin": {
"superblocktxt": "src/superblocktxt.js"
}
},
"node_modules/@istanbuljs/schema": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
@@ -8810,6 +8834,10 @@
"resolved": "services/references",
"link": true
},
"node_modules/@overleaf/saas-e2e": {
"resolved": "tools/saas-e2e",
"link": true
},
"node_modules/@overleaf/settings": {
"resolved": "libraries/settings",
"link": true
@@ -11901,6 +11929,16 @@
"@types/node": "*"
}
},
"node_modules/@types/adm-zip": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.7.tgz",
"integrity": "sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/aria-query": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
@@ -12483,6 +12521,13 @@
"integrity": "sha512-ZkC5IUqqIFPXx3ASTTybTzmQdwHwe2C0u3eL75ldQ6T9E9IWFJodn6hIfbZGab73DfyiHN4Xw15gNxUq2FbvBA==",
"dev": true
},
"node_modules/@types/pdf-parse": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@types/pdf-parse/-/pdf-parse-1.1.4.tgz",
"integrity": "sha512-+gbBHbNCVGGYw1S9lAIIvrHW47UYOhMIFUsJcMkMrzy1Jf0vulBN3XQIjPgnoOXveMuHnF3b57fXROnY/Or7eg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/pg": {
"version": "8.6.1",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
@@ -14573,6 +14618,16 @@
"node": ">=8.9"
}
},
"node_modules/adm-zip": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
"integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -15225,6 +15280,13 @@
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
},
"node_modules/async-lock": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
"integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==",
"dev": true,
"license": "MIT"
},
"node_modules/async-retry": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz",
@@ -17215,6 +17277,13 @@
"node": ">= 10.0"
}
},
"node_modules/clean-git-ref": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz",
"integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/clean-regexp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz",
@@ -19300,6 +19369,22 @@
"node": ">=0.10"
}
},
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
@@ -19605,6 +19690,13 @@
"integrity": "sha512-UfwfKGxT/Wm2KaxFSZsp7/+YOnAgIzxQXs86zu1IFMLU/+3ouxnEvXqPDn3yxSxlsO4r1B+I2GGQHsIthp6/7Q==",
"license": "Apache-2.0"
},
"node_modules/diff3": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz",
"integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==",
"dev": true,
"license": "MIT"
},
"node_modules/dijkstrajs": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz",
@@ -26461,6 +26553,79 @@
"node": ">=0.10.0"
}
},
"node_modules/isomorphic-git": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.29.0.tgz",
"integrity": "sha512-zWGqk8901cicvVEhVpN76AwKrS/TzHak2NQCtNXIAavpMIy/yqh+d/JtC9A8AUKZAauUdOyEWKI29tuCLAL+Zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"async-lock": "^1.4.1",
"clean-git-ref": "^2.0.1",
"crc-32": "^1.2.0",
"diff3": "0.0.3",
"ignore": "^5.1.4",
"minimisted": "^2.0.0",
"pako": "^1.0.10",
"path-browserify": "^1.0.1",
"pify": "^4.0.1",
"readable-stream": "^3.4.0",
"sha.js": "^2.4.9",
"simple-get": "^4.0.1"
},
"bin": {
"isogit": "cli.cjs"
},
"engines": {
"node": ">=12"
}
},
"node_modules/isomorphic-git/node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/isomorphic-git/node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/isomorphic-textencoder": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/isomorphic-textencoder/-/isomorphic-textencoder-1.0.1.tgz",
"integrity": "sha512-676hESgHullDdHDsj469hr+7t3i/neBKU9J7q1T4RHaWwLAsaQnywC0D1dIUId0YZ+JtVrShzuBk1soo0+GVcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-text-encoding": "^1.0.0"
}
},
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -27367,12 +27532,26 @@
"node": ">=4.0"
}
},
"node_modules/just-debounce-it": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/just-debounce-it/-/just-debounce-it-1.1.0.tgz",
"integrity": "sha512-87Nnc0qZKgBZuhFZjYVjSraic0x7zwjhaTMrCKlj0QYKH6lh0KbFzVnfu6LHan03NO7J8ygjeBeD0epejn5Zcg==",
"dev": true,
"license": "MIT"
},
"node_modules/just-extend": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
"integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==",
"dev": true
},
"node_modules/just-once": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/just-once/-/just-once-1.1.0.tgz",
"integrity": "sha512-+rZVpl+6VyTilK7vB/svlMPil4pxqIJZkbnN7DKZTOzyXfun6ZiFeq2Pk4EtCEHZ0VU4EkdFzG8ZK5F3PErcDw==",
"dev": true,
"license": "MIT"
},
"node_modules/jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
@@ -28517,6 +28696,32 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/mailtrap": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/mailtrap/-/mailtrap-3.4.0.tgz",
"integrity": "sha512-gegg90/gMY8hvfxB+WMtE8RRZyhQr90jUw00QOLApIAomItumqFBCpZv5IfG51EUKThu9+p7X4QdNA4buryenw==",
"dev": true,
"license": "MIT",
"dependencies": {
"axios": ">=0.27"
},
"engines": {
"node": ">=16.20.1",
"yarn": ">=1.22.17"
},
"peerDependencies": {
"@types/nodemailer": "^6.4.9",
"nodemailer": "^6.9.4"
},
"peerDependenciesMeta": {
"@types/nodemailer": {
"optional": true
},
"nodemailer": {
"optional": true
}
}
},
"node_modules/make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@@ -29316,6 +29521,19 @@
"node": ">=6"
}
},
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-document": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
@@ -29431,6 +29649,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minimisted": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz",
"integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==",
"dev": true,
"license": "MIT",
"dependencies": {
"minimist": "^1.2.5"
}
},
"node_modules/minipass": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
@@ -30242,6 +30470,13 @@
"node": ">=10.5.0"
}
},
"node_modules/node-ensure": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz",
"integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==",
"dev": true,
"license": "MIT"
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
@@ -31191,6 +31426,13 @@
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"dev": true,
"license": "(MIT AND Zlib)"
},
"node_modules/param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
@@ -31660,6 +31902,30 @@
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"node_modules/pdf-parse": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.1.tgz",
"integrity": "sha512-v6ZJ/efsBpGrGGknjtq9J/oC8tZWq0KWL5vQrk2GlzLEQPUDB1ex+13Rmidl1neNN358Jn9EHZw5y07FFtaC7A==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^3.1.0",
"node-ensure": "^0.0.0"
},
"engines": {
"node": ">=6.8.1"
}
},
"node_modules/pdf-parse/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/pdfjs-dist": {
"version": "4.10.38",
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.10.38.tgz",
@@ -36376,6 +36642,20 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/sha.js": {
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true,
"license": "(MIT AND BSD-3-Clause)",
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
},
"bin": {
"sha.js": "bin.js"
}
},
"node_modules/shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
@@ -36478,9 +36758,7 @@
"type": "consulting",
"url": "https://feross.org/support"
}
],
"optional": true,
"peer": true
]
},
"node_modules/simple-get": {
"version": "3.1.1",
@@ -45445,6 +45723,37 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"tools/saas-e2e": {
"name": "@overleaf/saas-e2e",
"devDependencies": {
"@isomorphic-git/lightning-fs": "^4.6.0",
"@testing-library/cypress": "^10.0.1",
"@types/adm-zip": "^0.5.5",
"@types/pdf-parse": "^1.1.4",
"@types/uuid": "^9.0.8",
"adm-zip": "^0.5.12",
"cypress": "13.13.2",
"isomorphic-git": "^1.25.10",
"mailtrap": "^3.4.0",
"pdf-parse": "^1.1.1",
"typescript": "^5.0.4",
"uuid": "^9.0.1"
}
},
"tools/saas-e2e/node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"dev": true,
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
}
}
}

View File

@@ -73,6 +73,7 @@
"services/third-party-datastore",
"services/third-party-references",
"services/tpdsworker",
"services/web"
"services/web",
"tools/saas-e2e"
]
}

View File

@@ -90,7 +90,11 @@ function formSubmitHelper(formEl) {
async function validateCaptcha(formEl) {
let captchaResponse
if (formEl.hasAttribute('captcha')) {
if (
formEl.hasAttribute('captcha') &&
// Disable captcha for E2E tests in dev-env.
!(process.env.NODE_ENV === 'development' && window.Cypress)
) {
if (
formEl.getAttribute('action') === '/login' &&
(await canSkipCaptcha(new FormData(formEl).get('email')))

View File

@@ -21,6 +21,9 @@ export function ReCaptcha2({
if (site && recaptchaDisabled[site]) {
return null
}
if (process.env.NODE_ENV === 'development' && window.Cypress) {
return null // Disable captcha for E2E tests in dev-env.
}
return (
<ReCAPTCHA
ref={recaptchaRef}

View File

@@ -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'
)