diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.js b/services/web/app/src/Features/Subscription/SubscriptionController.js index c231d6f0f3..a6564762be 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.js +++ b/services/web/app/src/Features/Subscription/SubscriptionController.js @@ -104,8 +104,106 @@ async function plansPage(req, res) { }) } -// get to show the recurly.js page async function paymentPage(req, res) { + try { + const assignment = await SplitTestHandler.promises.getAssignment( + req, + res, + 'subscription-pages-react' + ) + // get to show the recurly.js page + if (assignment.variant === 'active') { + await _paymentReactPage(req, res) + } else { + await _paymentAngularPage(req, res) + } + } catch (error) { + logger.warn( + { err: error }, + 'failed to get "subscription-pages-react" split test assignment' + ) + await _paymentAngularPage(req, res) + } +} + +/** + * @param {import("express").Request} req + * @param {import("express").Response} res + * @returns {Promise} + */ +async function _paymentReactPage(req, res) { + const user = SessionManager.getSessionUser(req.session) + const plan = PlansLocator.findLocalPlanInSettings(req.query.planCode) + if (!plan) { + return HttpErrorHandler.unprocessableEntity(req, res, 'Plan not found') + } + const hasSubscription = + await LimitationsManager.promises.userHasV1OrV2Subscription(user) + if (hasSubscription) { + res.redirect('/user/subscription?hasSubscription=true') + } else { + // LimitationsManager.userHasV2Subscription only checks Mongo. Double check with + // Recurly as well at this point (we don't do this most places for speed). + const valid = + await SubscriptionHandler.promises.validateNoSubscriptionInRecurly( + user._id + ) + if (!valid) { + res.redirect('/user/subscription?hasSubscription=true') + } else { + let currency = null + if (req.query.currency) { + const queryCurrency = req.query.currency.toUpperCase() + if (GeoIpLookup.isValidCurrencyParam(queryCurrency)) { + currency = queryCurrency + } + } + const { currencyCode: recommendedCurrency, countryCode } = + await GeoIpLookup.promises.getCurrencyCode( + (req.query ? req.query.ip : undefined) || req.ip + ) + if (recommendedCurrency && currency == null) { + currency = recommendedCurrency + } + + const refreshedPaymentPageAssignment = + await SplitTestHandler.promises.getAssignment( + req, + res, + 'payment-page-refresh' + ) + const useRefreshedPaymentPage = + refreshedPaymentPageAssignment && + refreshedPaymentPageAssignment.variant === 'refreshed-payment-page' + + await SplitTestHandler.promises.getAssignment( + req, + res, + 'student-check-modal' + ) + + // TODO + const template = useRefreshedPaymentPage + ? 'subscriptions/new-react' + : 'subscriptions/new-react' + + res.render(template, { + title: 'subscribe', + currency, + countryCode, + plan, + recurlyConfig: JSON.stringify({ + currency, + subdomain: Settings.apis.recurly.subdomain, + }), + showCouponField: !!req.query.scf, + showVatField: !!req.query.svf, + }) + } + } +} + +async function _paymentAngularPage(req, res) { const user = SessionManager.getSessionUser(req.session) const plan = PlansLocator.findLocalPlanInSettings(req.query.planCode) if (!plan) { @@ -177,6 +275,84 @@ async function paymentPage(req, res) { } async function userSubscriptionPage(req, res) { + try { + const assignment = await SplitTestHandler.promises.getAssignment( + req, + res, + 'subscription-pages-react' + ) + if (assignment.variant === 'active') { + await _userSubscriptionReactPage(req, res) + } else { + await _userSubscriptionAngularPage(req, res) + } + } catch (error) { + logger.warn( + { err: error }, + 'failed to get "subscription-pages-react" split test assignment' + ) + await _userSubscriptionAngularPage(req, res) + } +} + +/** + * @param {import("express").Request} req + * @param {import("express").Response} res + * @returns {Promise} + */ +async function _userSubscriptionReactPage(req, res) { + const user = SessionManager.getSessionUser(req.session) + const results = + await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( + user + ) + const { + personalSubscription, + memberGroupSubscriptions, + managedGroupSubscriptions, + currentInstitutionsWithLicence, + managedInstitutions, + managedPublishers, + v1SubscriptionStatus, + } = results + const hasSubscription = + await LimitationsManager.promises.userHasV1OrV2Subscription(user) + const fromPlansPage = req.query.hasSubscription + const plans = SubscriptionViewModelBuilder.buildPlansList( + personalSubscription ? personalSubscription.plan : undefined + ) + + AnalyticsManager.recordEventForSession(req.session, 'subscription-page-view') + + const cancelButtonAssignment = await SplitTestHandler.promises.getAssignment( + req, + res, + 'subscription-cancel-button' + ) + + const cancelButtonNewCopy = cancelButtonAssignment?.variant === 'new-copy' + + const data = { + title: 'your_subscription', + plans, + groupPlans: GroupPlansData, + user, + hasSubscription, + fromPlansPage, + personalSubscription, + memberGroupSubscriptions, + managedGroupSubscriptions, + managedInstitutions, + managedPublishers, + v1SubscriptionStatus, + currentInstitutionsWithLicence, + groupPlanModalOptions, + cancelButtonNewCopy, + } + res.render('subscriptions/dashboard-react', data) +} + +async function _userSubscriptionAngularPage(req, res) { const user = SessionManager.getSessionUser(req.session) const results = await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( @@ -302,6 +478,32 @@ async function createSubscription(req, res) { } async function successfulSubscription(req, res) { + try { + const assignment = await SplitTestHandler.promises.getAssignment( + req, + res, + 'subscription-pages-react' + ) + if (assignment.variant === 'active') { + await _successfulSubscriptionReact(req, res) + } else { + await _successfulSubscriptionAngular(req, res) + } + } catch (error) { + logger.warn( + { err: error }, + 'failed to get "subscription-pages-react" split test assignment' + ) + await _successfulSubscriptionAngular(req, res) + } +} + +/** + * @param {import("express").Request} req + * @param {import("express").Response} res + * @returns {Promise} + */ +async function _successfulSubscriptionReact(req, res) { const user = SessionManager.getSessionUser(req.session) const { personalSubscription } = await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( @@ -313,7 +515,27 @@ async function successfulSubscription(req, res) { if (!personalSubscription) { res.redirect('/user/subscription/plans') } else { - res.render('subscriptions/successful_subscription', { + res.render('subscriptions/successful-subscription-react', { + title: 'thank_you', + personalSubscription, + postCheckoutRedirect, + }) + } +} + +async function _successfulSubscriptionAngular(req, res) { + const user = SessionManager.getSessionUser(req.session) + const { personalSubscription } = + await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( + user + ) + + const postCheckoutRedirect = req.session?.postCheckoutRedirect + + if (!personalSubscription) { + res.redirect('/user/subscription/plans') + } else { + res.render('subscriptions/successful-subscription', { title: 'thank_you', personalSubscription, postCheckoutRedirect, @@ -337,8 +559,41 @@ function cancelSubscription(req, res, next) { }) } -function canceledSubscription(req, res, next) { - return res.render('subscriptions/canceled_subscription', { +async function canceledSubscription(req, res, next) { + try { + const assignment = await SplitTestHandler.promises.getAssignment( + req, + res, + 'subscription-pages-react' + ) + if (assignment.variant === 'active') { + await _canceledSubscriptionReact(req, res, next) + } else { + await _canceledSubscriptionAngular(req, res, next) + } + } catch (error) { + logger.warn( + { err: error }, + 'failed to get "subscription-pages-react" split test assignment' + ) + await _canceledSubscriptionAngular(req, res, next) + } +} + +/** + * @param {import("express").Request} req + * @param {import("express").Response} res + * @param {import("express").NextFunction} next + * @returns {Promise} + */ +function _canceledSubscriptionReact(req, res, next) { + return res.render('subscriptions/canceled-subscription-react', { + title: 'subscription_canceled', + }) +} + +function _canceledSubscriptionAngular(req, res, next) { + return res.render('subscriptions/canceled-subscription', { title: 'subscription_canceled', }) } diff --git a/services/web/app/src/Features/UserMembership/UserMembershipController.js b/services/web/app/src/Features/UserMembership/UserMembershipController.js index 23a306ffbb..547971d440 100644 --- a/services/web/app/src/Features/UserMembership/UserMembershipController.js +++ b/services/web/app/src/Features/UserMembership/UserMembershipController.js @@ -16,42 +16,99 @@ const Errors = require('../Errors/Errors') const EmailHelper = require('../Helpers/EmailHelper') const { csvAttachment } = require('../../infrastructure/Response') const { UserIsManagerError } = require('./UserMembershipErrors') +const SplitTestHandler = require('../SplitTests/SplitTestHandler') const CSVParser = require('json2csv').Parser +const logger = require('@overleaf/logger') + +async function index(req, res, next) { + try { + const assignment = await SplitTestHandler.promises.getAssignment( + req, + res, + 'subscription-pages-react' + ) + if (assignment.variant === 'active') { + await _indexReact(req, res, next) + } else { + await _indexAngular(req, res, next) + } + } catch (error) { + logger.warn( + { err: error }, + 'failed to get "subscription-pages-react" split test assignment' + ) + await _indexAngular(req, res, next) + } +} + +function _indexReact(req, res, next) { + const { entity, entityConfig } = req + return entity.fetchV1Data(function (error, entity) { + if (error != null) { + return next(error) + } + return UserMembershipHandler.getUsers( + entity, + entityConfig, + function (error, users) { + let entityName + if (error != null) { + return next(error) + } + const entityPrimaryKey = + entity[entityConfig.fields.primaryKey].toString() + if (entityConfig.fields.name) { + entityName = entity[entityConfig.fields.name] + } + return res.render('user_membership/index-react', { + name: entityName, + users, + groupSize: entityConfig.hasMembersLimit + ? entity.membersLimit + : undefined, + translations: entityConfig.translations, + paths: entityConfig.pathsFor(entityPrimaryKey), + }) + } + ) + }) +} + +function _indexAngular(req, res, next) { + const { entity, entityConfig } = req + return entity.fetchV1Data(function (error, entity) { + if (error != null) { + return next(error) + } + return UserMembershipHandler.getUsers( + entity, + entityConfig, + function (error, users) { + let entityName + if (error != null) { + return next(error) + } + const entityPrimaryKey = + entity[entityConfig.fields.primaryKey].toString() + if (entityConfig.fields.name) { + entityName = entity[entityConfig.fields.name] + } + return res.render('user_membership/index', { + name: entityName, + users, + groupSize: entityConfig.hasMembersLimit + ? entity.membersLimit + : undefined, + translations: entityConfig.translations, + paths: entityConfig.pathsFor(entityPrimaryKey), + }) + } + ) + }) +} module.exports = { - index(req, res, next) { - const { entity, entityConfig } = req - return entity.fetchV1Data(function (error, entity) { - if (error != null) { - return next(error) - } - return UserMembershipHandler.getUsers( - entity, - entityConfig, - function (error, users) { - let entityName - if (error != null) { - return next(error) - } - const entityPrimaryKey = - entity[entityConfig.fields.primaryKey].toString() - if (entityConfig.fields.name) { - entityName = entity[entityConfig.fields.name] - } - return res.render('user_membership/index', { - name: entityName, - users, - groupSize: entityConfig.hasMembersLimit - ? entity.membersLimit - : undefined, - translations: entityConfig.translations, - paths: entityConfig.pathsFor(entityPrimaryKey), - }) - } - ) - }) - }, - + index, add(req, res, next) { const { entity, entityConfig } = req const email = EmailHelper.parseEmail(req.body.email) @@ -96,7 +153,6 @@ module.exports = { } ) }, - remove(req, res, next) { const { entity, entityConfig } = req const { userId } = req.params @@ -135,7 +191,6 @@ module.exports = { } ) }, - exportCsv(req, res, next) { const { entity, entityConfig } = req const fields = ['email', 'last_logged_in_at', 'last_active_at'] @@ -152,14 +207,12 @@ module.exports = { } ) }, - new(req, res, next) { return res.render('user_membership/new', { entityName: req.params.name, entityId: req.params.id, }) }, - create(req, res, next) { const entityId = req.params.id const entityConfig = req.entityConfig diff --git a/services/web/app/views/subscriptions/canceled-subscription-react.pug b/services/web/app/views/subscriptions/canceled-subscription-react.pug new file mode 100644 index 0000000000..9cd6d7b9f8 --- /dev/null +++ b/services/web/app/views/subscriptions/canceled-subscription-react.pug @@ -0,0 +1,7 @@ +extends ../layout-marketing + +block entrypointVar + - entrypoint = 'pages/user/subscription/canceled-subscription' + +block content + main.content.content-alt#subscription-canceled-root diff --git a/services/web/app/views/subscriptions/canceled_subscription.pug b/services/web/app/views/subscriptions/canceled-subscription.pug similarity index 100% rename from services/web/app/views/subscriptions/canceled_subscription.pug rename to services/web/app/views/subscriptions/canceled-subscription.pug diff --git a/services/web/app/views/subscriptions/dashboard-react.pug b/services/web/app/views/subscriptions/dashboard-react.pug new file mode 100644 index 0000000000..211fbf2a62 --- /dev/null +++ b/services/web/app/views/subscriptions/dashboard-react.pug @@ -0,0 +1,17 @@ +extends ../layout-marketing + +block entrypointVar + - entrypoint = 'pages/user/subscription/dashboard' + +block append meta + meta(name="ol-managedInstitutions", data-type="json", content=managedInstitutions) + meta(name="ol-planCodesChangingAtTermEnd", data-type="json", content=plans.planCodesChangingAtTermEnd) + if (personalSubscription && personalSubscription.recurly) + meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey) + meta(name="ol-subscription" data-type="json" content=personalSubscription) + meta(name="ol-recommendedCurrency" content=personalSubscription.recurly.currency) + meta(name="ol-groupPlans" data-type="json" content=groupPlans) + meta(name="ol-groupPlanModalOptions" data-type="json" content=groupPlanModalOptions) + +block content + main.content.content-alt#subscription-dashboard-root diff --git a/services/web/app/views/subscriptions/new-react.pug b/services/web/app/views/subscriptions/new-react.pug new file mode 100644 index 0000000000..fd611d4c6c --- /dev/null +++ b/services/web/app/views/subscriptions/new-react.pug @@ -0,0 +1,14 @@ +extends ../layout-marketing + +include ./_new_mixins + +block entrypointVar + - entrypoint = 'pages/user/subscription/new' + +block append meta + meta(name="ol-countryCode" content=countryCode) + meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey) + meta(name="ol-recommendedCurrency" content=String(currency).slice(0,3)) + +block content + main.content.content-alt#subscription-new-root diff --git a/services/web/app/views/subscriptions/successful-subscription-react.pug b/services/web/app/views/subscriptions/successful-subscription-react.pug new file mode 100644 index 0000000000..8403c167e9 --- /dev/null +++ b/services/web/app/views/subscriptions/successful-subscription-react.pug @@ -0,0 +1,7 @@ +extends ../layout-marketing + +block entrypointVar + - entrypoint = 'pages/user/subscription/successful-subscription' + +block content + main.content.content-alt#subscription-success-root diff --git a/services/web/app/views/subscriptions/successful_subscription.pug b/services/web/app/views/subscriptions/successful-subscription.pug similarity index 100% rename from services/web/app/views/subscriptions/successful_subscription.pug rename to services/web/app/views/subscriptions/successful-subscription.pug diff --git a/services/web/app/views/user_membership/index-react.pug b/services/web/app/views/user_membership/index-react.pug new file mode 100644 index 0000000000..1deb768f12 --- /dev/null +++ b/services/web/app/views/user_membership/index-react.pug @@ -0,0 +1,12 @@ +extends ../layout-marketing + +block entrypointVar + - entrypoint = 'pages/user/membership/groups' + +block append meta + meta(name="ol-users", data-type="json", content=users) + meta(name="ol-paths", data-type="json", content=paths) + meta(name="ol-groupSize", data-type="json", content=groupSize) + +block content + main.content.content-alt#subscription-manage-groups-root diff --git a/services/web/frontend/js/features/membership/components/groups-root.tsx b/services/web/frontend/js/features/membership/components/groups-root.tsx new file mode 100644 index 0000000000..378b1630df --- /dev/null +++ b/services/web/frontend/js/features/membership/components/groups-root.tsx @@ -0,0 +1,5 @@ +function Root() { + return

React Manage Group Subscription

+} + +export default Root diff --git a/services/web/frontend/js/features/subscription/components/canceled-subscription/root.tsx b/services/web/frontend/js/features/subscription/components/canceled-subscription/root.tsx new file mode 100644 index 0000000000..011acb1760 --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/canceled-subscription/root.tsx @@ -0,0 +1,13 @@ +import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n' + +function Root() { + const { isReady } = useWaitForI18n() + + if (!isReady) { + return null + } + + return

React Subscription Canceled

+} + +export default Root diff --git a/services/web/frontend/js/features/subscription/components/dashboard/root.tsx b/services/web/frontend/js/features/subscription/components/dashboard/root.tsx new file mode 100644 index 0000000000..1287e4efd1 --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/dashboard/root.tsx @@ -0,0 +1,13 @@ +import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n' + +function Root() { + const { isReady } = useWaitForI18n() + + if (!isReady) { + return null + } + + return

React Subscription Dashboard

+} + +export default Root diff --git a/services/web/frontend/js/features/subscription/components/new/root.tsx b/services/web/frontend/js/features/subscription/components/new/root.tsx new file mode 100644 index 0000000000..15b05356dd --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/new/root.tsx @@ -0,0 +1,13 @@ +import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n' + +function Root() { + const { isReady } = useWaitForI18n() + + if (!isReady) { + return null + } + + return

React Subscription New

+} + +export default Root diff --git a/services/web/frontend/js/features/subscription/components/successful-subscription/root.tsx b/services/web/frontend/js/features/subscription/components/successful-subscription/root.tsx new file mode 100644 index 0000000000..d9f7c16d99 --- /dev/null +++ b/services/web/frontend/js/features/subscription/components/successful-subscription/root.tsx @@ -0,0 +1,13 @@ +import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n' + +function Root() { + const { isReady } = useWaitForI18n() + + if (!isReady) { + return null + } + + return

React Subscription Success

+} + +export default Root diff --git a/services/web/frontend/js/pages/user/membership/groups.js b/services/web/frontend/js/pages/user/membership/groups.js new file mode 100644 index 0000000000..a13e6f0c9a --- /dev/null +++ b/services/web/frontend/js/pages/user/membership/groups.js @@ -0,0 +1,7 @@ +import ReactDOM from 'react-dom' +import Root from '../../../features/membership/components/groups-root' + +const element = document.getElementById('subscription-manage-groups-root') +if (element) { + ReactDOM.render(, element) +} diff --git a/services/web/frontend/js/pages/user/subscription/base.js b/services/web/frontend/js/pages/user/subscription/base.js new file mode 100644 index 0000000000..0cdc796a67 --- /dev/null +++ b/services/web/frontend/js/pages/user/subscription/base.js @@ -0,0 +1,11 @@ +import 'jquery' +import 'bootstrap' +import './../../../utils/meta' +import './../../../utils/webpack-public-path' +import './../../../infrastructure/error-reporter' +import './../../../i18n' +import '../../../cdn-load-test' +import '../../../features/contact-form' +import '../../../features/event-tracking' +import '../../../features/cookie-banner' +import '../../../features/link-helpers/slow-link' diff --git a/services/web/frontend/js/pages/user/subscription/canceled-subscription.js b/services/web/frontend/js/pages/user/subscription/canceled-subscription.js new file mode 100644 index 0000000000..98fe7d178e --- /dev/null +++ b/services/web/frontend/js/pages/user/subscription/canceled-subscription.js @@ -0,0 +1,8 @@ +import './base' +import ReactDOM from 'react-dom' +import Root from '../../../features/subscription/components/canceled-subscription/root' + +const element = document.getElementById('subscription-canceled-root') +if (element) { + ReactDOM.render(, element) +} diff --git a/services/web/frontend/js/pages/user/subscription/dashboard.js b/services/web/frontend/js/pages/user/subscription/dashboard.js new file mode 100644 index 0000000000..96ea6d75a1 --- /dev/null +++ b/services/web/frontend/js/pages/user/subscription/dashboard.js @@ -0,0 +1,8 @@ +import './base' +import ReactDOM from 'react-dom' +import Root from '../../../features/subscription/components/dashboard/root' + +const element = document.getElementById('subscription-dashboard-root') +if (element) { + ReactDOM.render(, element) +} diff --git a/services/web/frontend/js/pages/user/subscription/new.js b/services/web/frontend/js/pages/user/subscription/new.js new file mode 100644 index 0000000000..336da947ef --- /dev/null +++ b/services/web/frontend/js/pages/user/subscription/new.js @@ -0,0 +1,8 @@ +import './base' +import ReactDOM from 'react-dom' +import Root from '../../../features/subscription/components/new/root' + +const element = document.getElementById('subscription-new-root') +if (element) { + ReactDOM.render(, element) +} diff --git a/services/web/frontend/js/pages/user/subscription/successful-subscription.js b/services/web/frontend/js/pages/user/subscription/successful-subscription.js new file mode 100644 index 0000000000..fde2a1aefc --- /dev/null +++ b/services/web/frontend/js/pages/user/subscription/successful-subscription.js @@ -0,0 +1,8 @@ +import './base' +import ReactDOM from 'react-dom' +import Root from '../../../features/subscription/components/successful-subscription/root' + +const element = document.getElementById('subscription-success-root') +if (element) { + ReactDOM.render(, element) +} diff --git a/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js b/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js index aa9fc8369e..1f14885969 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js +++ b/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js @@ -399,7 +399,7 @@ describe('SubscriptionController', function () { } ) this.res.render = (url, variables) => { - url.should.equal('subscriptions/successful_subscription') + url.should.equal('subscriptions/successful-subscription') assert.deepEqual(variables, { title: 'thank_you', personalSubscription: 'foo', diff --git a/services/web/test/unit/src/UserMembership/UserMembershipControllerTests.js b/services/web/test/unit/src/UserMembership/UserMembershipControllerTests.js index bb61d420dc..cd47c6c223 100644 --- a/services/web/test/unit/src/UserMembership/UserMembershipControllerTests.js +++ b/services/web/test/unit/src/UserMembership/UserMembershipControllerTests.js @@ -70,12 +70,19 @@ describe('UserMembershipController', function () { addUser: sinon.stub().yields(null, this.newUser), removeUser: sinon.stub().yields(null), } + this.SplitTestHandler = { + promises: { + getAssignment: sinon.stub().resolves({ variant: 'default' }), + }, + getAssignment: sinon.stub().yields(null, { variant: 'default' }), + } return (this.UserMembershipController = SandboxedModule.require( modulePath, { requires: { './UserMembershipErrors': { UserIsManagerError }, '../Authentication/SessionManager': this.SessionManager, + '../SplitTests/SplitTestHandler': this.SplitTestHandler, './UserMembershipHandler': this.UserMembershipHandler, }, } @@ -88,21 +95,20 @@ describe('UserMembershipController', function () { return (this.req.entityConfig = EntityConfigs.group) }) - it('get users', function (done) { - return this.UserMembershipController.index(this.req, { + it('get users', async function () { + return await this.UserMembershipController.index(this.req, { render: () => { sinon.assert.calledWithMatch( this.UserMembershipHandler.getUsers, this.subscription, { modelName: 'Subscription' } ) - return done() }, }) }) - it('render group view', function (done) { - return this.UserMembershipController.index(this.req, { + it('render group view', async function () { + return await this.UserMembershipController.index(this.req, { render: (viewPath, viewParams) => { expect(viewPath).to.equal('user_membership/index') expect(viewParams.users).to.deep.equal(this.users) @@ -111,14 +117,13 @@ describe('UserMembershipController', function () { expect(viewParams.paths.addMember).to.equal( `/manage/groups/${this.subscription._id}/invites` ) - return done() }, }) }) - it('render group managers view', function (done) { + it('render group managers view', async function () { this.req.entityConfig = EntityConfigs.groupManagers - return this.UserMembershipController.index(this.req, { + return await this.UserMembershipController.index(this.req, { render: (viewPath, viewParams) => { expect(viewPath).to.equal('user_membership/index') expect(viewParams.groupSize).to.equal(undefined) @@ -127,22 +132,20 @@ describe('UserMembershipController', function () { 'managers_management' ) expect(viewParams.paths.exportMembers).to.be.undefined - return done() }, }) }) - it('render institution view', function (done) { + it('render institution view', async function () { this.req.entity = this.institution this.req.entityConfig = EntityConfigs.institution - return this.UserMembershipController.index(this.req, { + return await this.UserMembershipController.index(this.req, { render: (viewPath, viewParams) => { expect(viewPath).to.equal('user_membership/index') expect(viewParams.name).to.equal('Test Institution Name') expect(viewParams.groupSize).to.equal(undefined) expect(viewParams.translations.title).to.equal('institution_account') expect(viewParams.paths.exportMembers).to.be.undefined - return done() }, }) })