Use a context function to replicate the behaviour of done

This is slightly different than done because done would resolve but I
think it is safer for the purpose done was being used in these changes.

GitOrigin-RevId: e60a912b82a8e544444a2776ea6aab7d2ea83bdb
This commit is contained in:
Andrew Rumble
2025-06-13 14:34:05 +01:00
committed by Copybot
parent 0a979e9bff
commit 55a02b2073
4 changed files with 224 additions and 98 deletions

View File

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

View File

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

View File

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

View File

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