From b1928cecefade85a0285582a4f5996bd3f96ed1b Mon Sep 17 00:00:00 2001 From: David <33458145+davidmcpowell@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:37:57 +0100 Subject: [PATCH] Merge pull request #17530 from overleaf/dp-teardown-onboarding-flow-split-test Teardown onboarding flow split test GitOrigin-RevId: 48e95e4e736772074cb68d195fc950a9da3aebcf --- .../Features/StaticPages/HomeController.js | 9 +-- .../web/app/src/Features/User/UserCreator.js | 8 -- services/web/locales/da.json | 1 - services/web/locales/de.json | 1 - services/web/locales/en.json | 1 - services/web/locales/fr.json | 1 - services/web/locales/pt.json | 1 - services/web/locales/sv.json | 1 - services/web/locales/zh-CN.json | 1 - .../test/acceptance/src/helpers/InitApp.js | 45 +++++++++++ .../web/test/acceptance/src/helpers/User.js | 74 ++++++++++++++++++- .../test/acceptance/src/helpers/UserHelper.js | 51 +++++++++++++ 12 files changed, 168 insertions(+), 26 deletions(-) diff --git a/services/web/app/src/Features/StaticPages/HomeController.js b/services/web/app/src/Features/StaticPages/HomeController.js index 897598a557..b7d914407e 100644 --- a/services/web/app/src/Features/StaticPages/HomeController.js +++ b/services/web/app/src/Features/StaticPages/HomeController.js @@ -7,7 +7,6 @@ const fs = require('fs') const ErrorController = require('../Errors/ErrorController') const SessionManager = require('../Authentication/SessionManager') -const SplitTestHandler = require('../SplitTests/SplitTestHandler') const { expressify } = require('@overleaf/promise-utils') const logger = require('@overleaf/logger') @@ -32,17 +31,11 @@ async function index(req, res) { async function home(req, res) { if (Features.hasFeature('homepage') && homepageExists) { - const onboardingFlowAssignment = - await SplitTestHandler.promises.getAssignment(req, res, 'onboarding-flow') AnalyticsManager.recordEventForSession(req.session, 'home-page-view', { page: req.path, }) - res.render('external/home/website-redesign/index', { - onboardingFlowVariant: onboardingFlowAssignment.variant, - hideNewsletterCheckbox: - onboardingFlowAssignment.variant === 'token-confirmation-odc', - }) + res.render('external/home/website-redesign/index') } else { res.redirect('/login') } diff --git a/services/web/app/src/Features/User/UserCreator.js b/services/web/app/src/Features/User/UserCreator.js index ea5760dd91..ebee80cd8a 100644 --- a/services/web/app/src/Features/User/UserCreator.js +++ b/services/web/app/src/Features/User/UserCreator.js @@ -7,7 +7,6 @@ const UserDeleter = require('./UserDeleter') const UserGetter = require('./UserGetter') const UserUpdater = require('./UserUpdater') const Analytics = require('../Analytics/AnalyticsManager') -const SplitTestHandler = require('../SplitTests/SplitTestHandler') const UserOnboardingEmailManager = require('./UserOnboardingEmailManager') const UserPostRegistrationAnalyticsManager = require('./UserPostRegistrationAnalyticsManager') const OError = require('@overleaf/o-error') @@ -37,16 +36,9 @@ async function _addAffiliation(user, affiliationOptions) { } async function recordRegistrationEvent(user) { - const onboardingFlowAssignment = - await SplitTestHandler.promises.getAssignmentForUser( - user._id, - 'onboarding-flow' - ) - try { const segmentation = { 'home-registration': 'default', - 'onboarding-flow': onboardingFlowAssignment.variant, } if (user.thirdPartyIdentifiers && user.thirdPartyIdentifiers.length > 0) { segmentation.provider = user.thirdPartyIdentifiers[0].providerId diff --git a/services/web/locales/da.json b/services/web/locales/da.json index 36446d3b78..c241af29ae 100644 --- a/services/web/locales/da.json +++ b/services/web/locales/da.json @@ -945,7 +945,6 @@ "new_tag": "Nyt tag", "new_tag_name": "Navn til nyt tag", "newsletter": "Nyhedsbrev", - "newsletter-accept": "Jeg vil gerne modtage e-mails om produkttilbud, virksomhedsnyheder og begivenheder.", "newsletter_info_note": "Du vil stadig modtage vigtige e-mails såsom projektinvitationer og sikkerhedsbeskeder (nulstilling af kode, kontoforbindelser, osv.).", "newsletter_info_subscribed": "Du er <0>tilmeldt til __appName__s nyhedsbrev. Hvis du foretrækker ikke at modtage disse e-mails, kan du altid framelde dig.", "newsletter_info_summary": "Hvert par måneder sender vi et nyhedsbrev som opsummerer de nyeste tilgængelige funktioner.", diff --git a/services/web/locales/de.json b/services/web/locales/de.json index 6fd75e4492..fdf6e6e2e1 100644 --- a/services/web/locales/de.json +++ b/services/web/locales/de.json @@ -937,7 +937,6 @@ "new_snippet_project": "Ohne Titel", "new_subscription_will_be_billed_immediately": "Dein neues Abonnement wird umgehend mit deiner aktuellen Zahlungsmethode abgerechnet.", "newsletter": "Newsletter", - "newsletter-accept": "Ich möchte E-Mails zu Produktangeboten, Neuigkeiten und Veranstaltungen des Unternehmens erhalten.", "newsletter_info_note": "Bitte beachte: Du erhältst weiterhin wichtige E-Mails wie Projekteinladungen und Sicherheitsbenachrichtigungen (Passwortzurücksetzung, Kontoverknüpfung usw.).", "newsletter_info_subscribed": "Du hast den __appName__-Newsletter <0>abonniert. Wenn du diese E-Mails lieber nicht erhalten möchtest, kannst du dich jederzeit abmelden.", "newsletter_info_summary": "Alle paar Monate versenden wir einen Newsletter mit einer Zusammenfassung der neu verfügbaren Funktionen.", diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 00a0925156..75449e2358 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1177,7 +1177,6 @@ "new_tag": "New Tag", "new_tag_name": "New tag name", "newsletter": "Newsletter", - "newsletter-accept": "I’d like emails about product offers and company news and events.", "newsletter_info_note": "Please note: you will still receive important emails, such as project invites and security notifications (password resets, account linking, etc).", "newsletter_info_subscribed": "You are currently <0>subscribed to the __appName__ newsletter. If you would prefer not to receive this email then you can unsubscribe at any time.", "newsletter_info_summary": "Every few months we send a newsletter out summarizing the new features available.", diff --git a/services/web/locales/fr.json b/services/web/locales/fr.json index e255c98eb8..241037e259 100644 --- a/services/web/locales/fr.json +++ b/services/web/locales/fr.json @@ -606,7 +606,6 @@ "new_password": "Nouveau mot de passe", "new_project": "Nouveau projet", "new_snippet_project": "Sans titre", - "newsletter-accept": "Je souhaite recevoir des courriels portant sur des offres de produits et sur les actualités et événements de notre entreprise.", "next_payment_of_x_collectected_on_y": "Le prochain paiement de <0>__paymentAmmount__ sera débité le <1>__collectionDate__.", "nl": "Hollandais", "no": "Norvégien", diff --git a/services/web/locales/pt.json b/services/web/locales/pt.json index f734cebfd4..7430533041 100644 --- a/services/web/locales/pt.json +++ b/services/web/locales/pt.json @@ -413,7 +413,6 @@ "new_name": "Novo Nome", "new_password": "Nova Senha", "new_project": "Novo Projeto", - "newsletter-accept": "Gostaria de receber e-mails sobre ofertas de produtos, notícias e eventos da empresa.", "next_payment_of_x_collectected_on_y": "O próximo pagamento de <0>__paymentAmmount__ será coletado em <1>__collectionDate__", "nl": "Holandês", "no": "Noroeguês", diff --git a/services/web/locales/sv.json b/services/web/locales/sv.json index 4eb11f27b7..7c7aafcd48 100644 --- a/services/web/locales/sv.json +++ b/services/web/locales/sv.json @@ -579,7 +579,6 @@ "new_password": "Nytt lösenord", "new_project": "Nytt projekt", "new_snippet_project": "Namnlös", - "newsletter-accept": "Jag vill få e-post om produkterbjudanden, nyheter och evenemang från företaget.", "next_payment_of_x_collectected_on_y": "Nästa betalning på <0>__paymentAmmount__ kommer att genomföras den <1>__collectionDate__", "nl": "Holländska", "no": "Norska", diff --git a/services/web/locales/zh-CN.json b/services/web/locales/zh-CN.json index bafdac7fb3..7d78be23a1 100644 --- a/services/web/locales/zh-CN.json +++ b/services/web/locales/zh-CN.json @@ -1153,7 +1153,6 @@ "new_tag": "新建标签", "new_tag_name": "新标签名", "newsletter": "电子邮件", - "newsletter-accept": "我想要关于产品报价和公司新闻和事件的电子邮件。", "newsletter_info_note": "请注意:您仍然会收到重要的电子邮件,例如项目邀请和安全通知(密码重置、帐户链接等)。", "newsletter_info_subscribed": "您当前<0>订阅了__appName__ 新闻资讯。 如果您不想收到此电子邮件,则可以随时取消订阅。", "newsletter_info_summary": "每隔几个月,我们就会发送一份简讯,总结可用的新功能。", diff --git a/services/web/test/acceptance/src/helpers/InitApp.js b/services/web/test/acceptance/src/helpers/InitApp.js index bda55d1504..7c7f770c3c 100644 --- a/services/web/test/acceptance/src/helpers/InitApp.js +++ b/services/web/test/acceptance/src/helpers/InitApp.js @@ -8,6 +8,50 @@ const MockReCAPTCHAApi = require('../mocks/MockReCaptchaApi') const { gracefulShutdown, } = require('../../../../app/src/infrastructure/GracefulShutdown') +const { app } = require('../../../../app/src/infrastructure/Server') + +/** + * Inject an endpoint to get the current users session into our app. This + * endpoint should only be available when running in the test environment. + * It is used to retrieve an email confirmation code when registering a + * new user account in acceptance tests. + */ +const addSessionEndpoint = app => { + const stack = app._router.stack + + stack.forEach(layer => { + if (layer.name !== 'router' || !layer.handle || !layer.handle.stack) { + return + } + + // We want to position our /dev/session endpoint next to the /dev/csrf + // endpoint so we check each router for the presence of this path. + const newRouteIndex = layer.handle.stack.findIndex( + route => + route && + route.route && + route.route.path && + route.route.path === '/dev/csrf' + ) + + if (newRouteIndex !== -1) { + // We add our new endpoint to the end of the router stack. + layer.handle.get('/dev/session', (req, res) => { + return res.json(req.session) + }) + + const routeStack = layer.handle.stack + const sessionRoute = routeStack[routeStack.length - 1] + + // Then we reposition it next to the /dev/csrf endpoint. + layer.handle.stack = [ + ...routeStack.slice(0, newRouteIndex), + sessionRoute, + ...routeStack.slice(newRouteIndex, routeStack.length - 1), + ] + } + }) +} logger.logger.level('error') @@ -18,6 +62,7 @@ MockReCAPTCHAApi.initialize(2222) let server before('start main app', function (done) { + addSessionEndpoint(app) server = App.listen(23000, 'localhost', done) }) diff --git a/services/web/test/acceptance/src/helpers/User.js b/services/web/test/acceptance/src/helpers/User.js index cbdcc3da50..aeeb074cf1 100644 --- a/services/web/test/acceptance/src/helpers/User.js +++ b/services/web/test/acceptance/src/helpers/User.js @@ -32,6 +32,46 @@ class User { }) } + getSession(callback) { + this.request.get( + { + url: '/dev/session', + }, + (err, response, body) => { + if (err != null) { + return callback(err) + } + if (response.statusCode !== 200) { + return callback( + new Error( + `get session failed: status=${ + response.statusCode + } body=${JSON.stringify(body)}` + ) + ) + } + + const session = JSON.parse(response.body) + callback(null, session) + } + ) + } + + getEmailConfirmationCode(callback) { + this.getSession((err, session) => { + if (err != null) { + return callback(err) + } + + const code = session.pendingUserRegistration?.confirmCode + if (!code) { + return callback(new Error('No confirmation code found in session')) + } + + callback(null, code) + }) + } + resetCookies() { this.jar = request.jar() this.request = request.defaults({ @@ -114,12 +154,40 @@ class User { ) ) } - db.users.findOne({ email: this.email }, (error, user) => { + + this.getEmailConfirmationCode((error, code) => { if (error != null) { return callback(error) } - this.setExtraAttributes(user) - callback(null, user) + + this.request.post( + { + url: '/registration/confirm-email', + json: { code }, + }, + (error, response, body) => { + if (error != null) { + return callback(error) + } + if (response.statusCode !== 200) { + return callback( + new Error( + `email confirmation failed: status=${ + response.statusCode + } body=${JSON.stringify(body)}` + ) + ) + } + + db.users.findOne({ email: this.email }, (error, user) => { + if (error != null) { + return callback(error) + } + this.setExtraAttributes(user) + callback(null, user) + }) + } + ) }) } ) diff --git a/services/web/test/acceptance/src/helpers/UserHelper.js b/services/web/test/acceptance/src/helpers/UserHelper.js index 7949d2c959..996751fc39 100644 --- a/services/web/test/acceptance/src/helpers/UserHelper.js +++ b/services/web/test/acceptance/src/helpers/UserHelper.js @@ -140,6 +140,33 @@ class UserHelper { this._csrfToken = body } + /** + * Requests user session + */ + async getSession() { + const response = await this.fetch('/dev/session') + const body = await response.text() + + if (response.status !== 200) { + throw new Error( + `get session failed: status=${response.status} body=${JSON.stringify( + body + )}` + ) + } + return JSON.parse(body) + } + + async getEmailConfirmationCode() { + const session = await this.getSession() + + const code = session.pendingUserRegistration?.confirmCode + if (!code) { + throw new Error('No confirmation code found in session') + } + return code + } + /** * Make request to POST /logout * @param {object} [options] options to pass to request @@ -353,6 +380,30 @@ class UserHelper { `cannot register intitutional email: ${options.json.email}` ) } + + const code = await userHelper.getEmailConfirmationCode() + + const confirmationResponse = await userHelper.fetch( + '/registration/confirm-email', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ code }), + ...options, + } + ) + + if (confirmationResponse.status !== 200) { + throw new Error( + `email confirmation failed: status=${ + response.status + } body=${JSON.stringify(body)}` + ) + } + userHelper.user = await UserGetter.promises.getUser({ email: userData.email, })