diff --git a/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs b/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs index 586aaf195d..b1fc8cf2fa 100644 --- a/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs +++ b/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs @@ -80,12 +80,16 @@ describe('BetaProgramController', function () { describe('optIn', function () { it("should redirect to '/beta/participate'", async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.redirectedTo.should.equal('/beta/participate') resolve() } - ctx.BetaProgramController.optIn(ctx.req, ctx.res) + ctx.BetaProgramController.optIn( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) @@ -134,37 +138,49 @@ describe('BetaProgramController', function () { describe('optOut', function () { it("should redirect to '/beta/participate'", async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.res.redirectedTo).to.equal('/beta/participate') resolve() } - ctx.BetaProgramController.optOut(ctx.req, ctx.res) + ctx.BetaProgramController.optOut( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should not call next with an error', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.next.callCount.should.equal(0) resolve() } - ctx.BetaProgramController.optOut(ctx.req, ctx.res) + ctx.BetaProgramController.optOut( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should call BetaProgramHandler.optOut', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.BetaProgramHandler.promises.optOut.callCount.should.equal(1) resolve() } - ctx.BetaProgramController.optOut(ctx.req, ctx.res) + ctx.BetaProgramController.optOut( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should invoke the session maintenance', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.SplitTestSessionHandler.promises.sessionMaintenance.should.have.been.calledWith( ctx.req, @@ -172,7 +188,11 @@ describe('BetaProgramController', function () { ) resolve() } - ctx.BetaProgramController.optOut(ctx.req, ctx.res) + ctx.BetaProgramController.optOut( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) @@ -208,12 +228,16 @@ describe('BetaProgramController', function () { }) it('should render the opt-in page', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.res.renderedTemplate).to.equal('beta_program/opt_in') resolve() } - ctx.BetaProgramController.optInPage(ctx.req, ctx.res) + ctx.BetaProgramController.optInPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) diff --git a/services/web/test/unit/src/Contact/ContactController.test.mjs b/services/web/test/unit/src/Contact/ContactController.test.mjs index fa23677a5b..06dd5b768a 100644 --- a/services/web/test/unit/src/Contact/ContactController.test.mjs +++ b/services/web/test/unit/src/Contact/ContactController.test.mjs @@ -89,7 +89,7 @@ describe('ContactController', function () { }) it('should populate the users contacts ids', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.UserGetter.promises.getUsers).to.have.been.calledWith( ctx.contact_ids, @@ -102,12 +102,16 @@ describe('ContactController', function () { ) resolve() } - ctx.ContactController.getContacts(ctx.req, ctx.res) + ctx.ContactController.getContacts( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should fire the getContact module hook', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.Modules.promises.hooks.fire).to.have.been.calledWith( 'getContacts', @@ -115,12 +119,16 @@ describe('ContactController', function () { ) resolve() } - ctx.ContactController.getContacts(ctx.req, ctx.res) + ctx.ContactController.getContacts( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should return a formatted list of contacts in contact list order, without holding accounts', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.json.args[0][0].contacts.should.deep.equal([ { @@ -140,7 +148,11 @@ describe('ContactController', function () { ]) resolve() } - ctx.ContactController.getContacts(ctx.req, ctx.res) + ctx.ContactController.getContacts( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) }) diff --git a/services/web/test/unit/src/User/UserPagesController.test.mjs b/services/web/test/unit/src/User/UserPagesController.test.mjs index 8afc49c40f..f6252faa94 100644 --- a/services/web/test/unit/src/User/UserPagesController.test.mjs +++ b/services/web/test/unit/src/User/UserPagesController.test.mjs @@ -161,22 +161,25 @@ describe('UserPagesController', function () { describe('registerPage', function () { it('should render the register page', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedTemplate.should.equal('user/register') resolve() } - ctx.UserPagesController.registerPage(ctx.req, ctx.res) + ctx.UserPagesController.registerPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should set sharedProjectData', async function (ctx) { - await new Promise(resolve => { - ctx.req.session.sharedProjectData = { - project_name: 'myProject', - user_first_name: 'user_first_name_here', - } - + ctx.req.session.sharedProjectData = { + project_name: 'myProject', + user_first_name: 'user_first_name_here', + } + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedVariables.sharedProjectData.project_name.should.equal( 'myProject' @@ -186,12 +189,16 @@ describe('UserPagesController', function () { ) resolve() } - ctx.UserPagesController.registerPage(ctx.req, ctx.res) + ctx.UserPagesController.registerPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should set newTemplateData', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.req.session.templateData = { templateName: 'templateName' } ctx.res.callback = () => { @@ -200,12 +207,16 @@ describe('UserPagesController', function () { ) resolve() } - ctx.UserPagesController.registerPage(ctx.req, ctx.res) + ctx.UserPagesController.registerPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should not set the newTemplateData if there is nothing in the session', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { assert.equal( ctx.res.renderedVariables.newTemplateData.templateName, @@ -213,19 +224,27 @@ describe('UserPagesController', function () { ) resolve() } - ctx.UserPagesController.registerPage(ctx.req, ctx.res) + ctx.UserPagesController.registerPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) }) describe('loginForm', function () { it('should render the login page', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedTemplate.should.equal('user/login') resolve() } - ctx.UserPagesController.loginPage(ctx.req, ctx.res) + ctx.UserPagesController.loginPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) @@ -239,7 +258,7 @@ describe('UserPagesController', function () { }) it('should set a redirect', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = page => { ctx.AuthenticationController.setRedirectInSession.callCount.should.equal( 1 @@ -249,7 +268,11 @@ describe('UserPagesController', function () { ).to.equal(ctx.req.query.redir) resolve() } - ctx.UserPagesController.loginPage(ctx.req, ctx.res) + ctx.UserPagesController.loginPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) }) @@ -261,17 +284,21 @@ describe('UserPagesController', function () { }) it('should render user/sessions', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedTemplate.should.equal('user/sessions') resolve() } - ctx.UserPagesController.sessionsPage(ctx.req, ctx.res) + ctx.UserPagesController.sessionsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should include current session data in the view', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.res.renderedVariables.currentSession).to.deep.equal({ ip_address: '1.1.1.1', @@ -279,17 +306,25 @@ describe('UserPagesController', function () { }) resolve() } - ctx.UserPagesController.sessionsPage(ctx.req, ctx.res) + ctx.UserPagesController.sessionsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should have called getAllUserSessions', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = page => { ctx.UserSessionsManager.getAllUserSessions.callCount.should.equal(1) resolve() } - ctx.UserPagesController.sessionsPage(ctx.req, ctx.res) + ctx.UserPagesController.sessionsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) @@ -320,28 +355,36 @@ describe('UserPagesController', function () { }) it('render page with subscribed status', async function (ctx) { - await new Promise(resolve => { - ctx.NewsletterManager.subscribed.yields(null, true) + ctx.NewsletterManager.subscribed.yields(null, true) + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedTemplate.should.equal('user/email-preferences') ctx.res.renderedVariables.title.should.equal('newsletter_info_title') ctx.res.renderedVariables.subscribed.should.equal(true) resolve() } - ctx.UserPagesController.emailPreferencesPage(ctx.req, ctx.res) + ctx.UserPagesController.emailPreferencesPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('render page with unsubscribed status', async function (ctx) { - await new Promise(resolve => { - ctx.NewsletterManager.subscribed.yields(null, false) + ctx.NewsletterManager.subscribed.yields(null, false) + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedTemplate.should.equal('user/email-preferences') ctx.res.renderedVariables.title.should.equal('newsletter_info_title') ctx.res.renderedVariables.subscribed.should.equal(false) resolve() } - ctx.UserPagesController.emailPreferencesPage(ctx.req, ctx.res) + ctx.UserPagesController.emailPreferencesPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) }) @@ -355,54 +398,70 @@ describe('UserPagesController', function () { }) it('should render user/settings', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedTemplate.should.equal('user/settings') resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should send user', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedVariables.user.id.should.equal(ctx.user._id) ctx.res.renderedVariables.user.email.should.equal(ctx.user.email) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it("should set 'shouldAllowEditingDetails' to true", async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedVariables.shouldAllowEditingDetails.should.equal(true) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should restructure thirdPartyIdentifiers data for template use', async function (ctx) { - await new Promise(resolve => { - const expectedResult = { - google: 'testId', - } + const expectedResult = { + google: 'testId', + } + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.res.renderedVariables.thirdPartyIds).to.include( expectedResult ) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it("should set and clear 'projectSyncSuccessMessage'", async function (ctx) { - await new Promise(resolve => { - ctx.req.session.projectSyncSuccessMessage = 'Some Sync Success' + ctx.req.session.projectSyncSuccessMessage = 'Some Sync Success' + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedVariables.projectSyncSuccessMessage.should.equal( 'Some Sync Success' @@ -410,12 +469,16 @@ describe('UserPagesController', function () { expect(ctx.req.session.projectSyncSuccessMessage).to.not.exist resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should cast refProviders to booleans', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect(ctx.res.renderedVariables.user.refProviders).to.deep.equal({ mendeley: true, @@ -424,53 +487,60 @@ describe('UserPagesController', function () { }) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should send the correct managed user admin email', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect( ctx.res.renderedVariables.currentManagedUserAdminEmail ).to.equal(ctx.adminEmail) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) it('should send info for groups with SSO enabled', async function (ctx) { - await new Promise(resolve => { - ctx.user.enrollment = { - sso: [ - { - groupId: 'abc123abc123', - primary: true, - linkedAt: new Date(), - }, - ], - } - const group1 = { - _id: 'abc123abc123', - teamName: 'Group SSO Rulz', - admin_id: { - email: 'admin.email@ssolove.com', + ctx.user.enrollment = { + sso: [ + { + groupId: 'abc123abc123', + primary: true, + linkedAt: new Date(), }, - linked: true, - } - const group2 = { - _id: 'def456def456', - admin_id: { - email: 'someone.else@noname.co.uk', - }, - linked: false, - } - - ctx.Modules.promises.hooks.fire - .withArgs('getUserGroupsSSOEnrollmentStatus') - .resolves([[group1, group2]]) + ], + } + const group1 = { + _id: 'abc123abc123', + teamName: 'Group SSO Rulz', + admin_id: { + email: 'admin.email@ssolove.com', + }, + linked: true, + } + const group2 = { + _id: 'def456def456', + admin_id: { + email: 'someone.else@noname.co.uk', + }, + linked: false, + } + ctx.Modules.promises.hooks.fire + .withArgs('getUserGroupsSSOEnrollmentStatus') + .resolves([[group1, group2]]) + await new Promise((resolve, reject) => { ctx.res.callback = () => { expect( ctx.res.renderedVariables.memberOfSSOEnabledGroups @@ -491,7 +561,11 @@ describe('UserPagesController', function () { resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) @@ -505,14 +579,18 @@ describe('UserPagesController', function () { }) it('should set "shouldAllowEditingDetails" to false', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedVariables.shouldAllowEditingDetails.should.equal( false ) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) }) @@ -527,14 +605,18 @@ describe('UserPagesController', function () { }) it('should set "shouldAllowEditingDetails" to false', async function (ctx) { - await new Promise(resolve => { + await new Promise((resolve, reject) => { ctx.res.callback = () => { ctx.res.renderedVariables.shouldAllowEditingDetails.should.equal( false ) resolve() } - ctx.UserPagesController.settingsPage(ctx.req, ctx.res) + ctx.UserPagesController.settingsPage( + ctx.req, + ctx.res, + ctx.rejectOnError(reject) + ) }) }) }) diff --git a/services/web/test/unit/vitest_bootstrap.mjs b/services/web/test/unit/vitest_bootstrap.mjs index 5a39b2d587..e00720c5d6 100644 --- a/services/web/test/unit/vitest_bootstrap.mjs +++ b/services/web/test/unit/vitest_bootstrap.mjs @@ -36,6 +36,14 @@ vi.mock('@overleaf/logger', async () => { }) beforeEach(ctx => { + // This function is a utility to duplicate the behaviour of passing `done` in place of `next` in an express route handler. + ctx.rejectOnError = reject => { + return err => { + if (err) { + reject(err) + } + } + } ctx.logger = logger })