|
|
@@ -12,7 +12,7 @@ describe('UserController', function () {
|
|
|
this.user = {
|
|
|
_id: this.user_id,
|
|
|
email: 'email@overleaf.com',
|
|
|
- save: sinon.stub().callsArgWith(0),
|
|
|
+ save: sinon.stub().resolves(),
|
|
|
ace: {},
|
|
|
}
|
|
|
|
|
|
@@ -34,29 +34,37 @@ describe('UserController', function () {
|
|
|
ip: '0:0:0:0',
|
|
|
query: {},
|
|
|
headers: {},
|
|
|
+ logger: {
|
|
|
+ addFields: sinon.stub(),
|
|
|
+ },
|
|
|
}
|
|
|
|
|
|
- this.UserDeleter = { deleteUser: sinon.stub().yields() }
|
|
|
+ this.UserDeleter = { promises: { deleteUser: sinon.stub().resolves() } }
|
|
|
+
|
|
|
this.UserGetter = {
|
|
|
- getUser: sinon.stub().yields(null, this.user),
|
|
|
promises: { getUser: sinon.stub().resolves(this.user) },
|
|
|
}
|
|
|
- this.User = { findById: sinon.stub().yields(null, this.user) }
|
|
|
- this.NewsLetterManager = {
|
|
|
- subscribe: sinon.stub().yields(),
|
|
|
- unsubscribe: sinon.stub().yields(),
|
|
|
+
|
|
|
+ this.User = {
|
|
|
+ findById: sinon
|
|
|
+ .stub()
|
|
|
+ .returns({ exec: sinon.stub().resolves(this.user) }),
|
|
|
}
|
|
|
- this.AuthenticationController = {
|
|
|
- establishUserSession: sinon.stub().callsArg(2),
|
|
|
+
|
|
|
+ this.NewsLetterManager = {
|
|
|
+ promises: {
|
|
|
+ subscribe: sinon.stub().resolves(),
|
|
|
+ unsubscribe: sinon.stub().resolves(),
|
|
|
+ },
|
|
|
}
|
|
|
+
|
|
|
this.SessionManager = {
|
|
|
getLoggedInUserId: sinon.stub().returns(this.user._id),
|
|
|
getSessionUser: sinon.stub().returns(this.req.session.user),
|
|
|
setInSessionUser: sinon.stub(),
|
|
|
}
|
|
|
+
|
|
|
this.AuthenticationManager = {
|
|
|
- authenticate: sinon.stub(),
|
|
|
- validatePassword: sinon.stub(),
|
|
|
promises: {
|
|
|
authenticate: sinon.stub(),
|
|
|
setUserPassword: sinon.stub(),
|
|
|
@@ -65,24 +73,29 @@ describe('UserController', function () {
|
|
|
.stub()
|
|
|
.returns({ type: 'error', key: 'some-key' }),
|
|
|
}
|
|
|
+
|
|
|
this.UserUpdater = {
|
|
|
- changeEmailAddress: sinon.stub(),
|
|
|
promises: {
|
|
|
+ changeEmailAddress: sinon.stub().resolves(),
|
|
|
confirmEmail: sinon.stub().resolves(),
|
|
|
addAffiliationForNewUser: sinon.stub().resolves(),
|
|
|
},
|
|
|
}
|
|
|
+
|
|
|
this.settings = { siteUrl: 'sharelatex.example.com' }
|
|
|
- this.UserHandler = { populateTeamInvites: sinon.stub().callsArgWith(1) }
|
|
|
+
|
|
|
+ this.UserHandler = {
|
|
|
+ promises: { populateTeamInvites: sinon.stub().resolves() },
|
|
|
+ }
|
|
|
+
|
|
|
this.UserSessionsManager = {
|
|
|
- trackSession: sinon.stub(),
|
|
|
- untrackSession: sinon.stub(),
|
|
|
- revokeAllUserSessions: sinon.stub().callsArgWith(2, null),
|
|
|
promises: {
|
|
|
getAllUserSessions: sinon.stub().resolves(),
|
|
|
revokeAllUserSessions: sinon.stub().resolves(),
|
|
|
+ untrackSession: sinon.stub().resolves(),
|
|
|
},
|
|
|
}
|
|
|
+
|
|
|
this.HttpErrorHandler = {
|
|
|
badRequest: sinon.stub(),
|
|
|
conflict: sinon.stub(),
|
|
|
@@ -97,7 +110,24 @@ describe('UserController', function () {
|
|
|
.withArgs('https://evil.com')
|
|
|
.returns(undefined)
|
|
|
this.UrlHelper.getSafeRedirectPath.returnsArg(0)
|
|
|
- this.acceptsJson = sinon.stub().returns(false)
|
|
|
+
|
|
|
+ this.Features = {
|
|
|
+ hasFeature: sinon.stub(),
|
|
|
+ }
|
|
|
+
|
|
|
+ this.UserAuditLogHandler = {
|
|
|
+ promises: {
|
|
|
+ addEntry: sinon.stub().resolves(),
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ this.RequestContentTypeDetection = {
|
|
|
+ acceptsJson: sinon.stub().returns(false),
|
|
|
+ }
|
|
|
+
|
|
|
+ this.EmailHandler = {
|
|
|
+ promises: { sendEmail: sinon.stub().resolves() },
|
|
|
+ }
|
|
|
|
|
|
this.UserController = SandboxedModule.require(modulePath, {
|
|
|
requires: {
|
|
|
@@ -105,37 +135,22 @@ describe('UserController', function () {
|
|
|
'./UserGetter': this.UserGetter,
|
|
|
'./UserDeleter': this.UserDeleter,
|
|
|
'./UserUpdater': this.UserUpdater,
|
|
|
- '../../models/User': {
|
|
|
- User: this.User,
|
|
|
- },
|
|
|
+ '../../models/User': { User: this.User },
|
|
|
'../Newsletter/NewsletterManager': this.NewsLetterManager,
|
|
|
'../Authentication/AuthenticationController':
|
|
|
this.AuthenticationController,
|
|
|
'../Authentication/SessionManager': this.SessionManager,
|
|
|
'../Authentication/AuthenticationManager': this.AuthenticationManager,
|
|
|
- '../../infrastructure/Features': (this.Features = {
|
|
|
- hasFeature: sinon.stub(),
|
|
|
- }),
|
|
|
- './UserAuditLogHandler': (this.UserAuditLogHandler = {
|
|
|
- promises: {
|
|
|
- addEntry: sinon.stub().resolves(),
|
|
|
- },
|
|
|
- }),
|
|
|
+ '../../infrastructure/Features': this.Features,
|
|
|
+ './UserAuditLogHandler': this.UserAuditLogHandler,
|
|
|
'./UserHandler': this.UserHandler,
|
|
|
'./UserSessionsManager': this.UserSessionsManager,
|
|
|
'../Errors/HttpErrorHandler': this.HttpErrorHandler,
|
|
|
'@overleaf/settings': this.settings,
|
|
|
- '@overleaf/metrics': {
|
|
|
- inc() {},
|
|
|
- },
|
|
|
'@overleaf/o-error': OError,
|
|
|
- '../Email/EmailHandler': (this.EmailHandler = {
|
|
|
- sendEmail: sinon.stub(),
|
|
|
- promises: { sendEmail: sinon.stub().resolves() },
|
|
|
- }),
|
|
|
- '../../infrastructure/RequestContentTypeDetection': {
|
|
|
- acceptsJson: this.acceptsJson,
|
|
|
- },
|
|
|
+ '../Email/EmailHandler': this.EmailHandler,
|
|
|
+ '../../infrastructure/RequestContentTypeDetection':
|
|
|
+ this.RequestContentTypeDetection,
|
|
|
},
|
|
|
})
|
|
|
|
|
|
@@ -154,13 +169,11 @@ describe('UserController', function () {
|
|
|
beforeEach(function () {
|
|
|
this.req.body.password = 'wat'
|
|
|
this.req.logout = sinon.stub()
|
|
|
- this.req.session.destroy = sinon.stub().callsArgWith(0, null)
|
|
|
+ this.req.session.destroy = sinon.stub().yields()
|
|
|
this.SessionManager.getLoggedInUserId = sinon
|
|
|
.stub()
|
|
|
.returns(this.user._id)
|
|
|
- this.AuthenticationManager.authenticate = sinon
|
|
|
- .stub()
|
|
|
- .callsArgWith(2, null, this.user)
|
|
|
+ this.AuthenticationManager.promises.authenticate.resolves(this.user)
|
|
|
})
|
|
|
|
|
|
it('should send 200', function (done) {
|
|
|
@@ -173,10 +186,12 @@ describe('UserController', function () {
|
|
|
|
|
|
it('should try to authenticate user', function (done) {
|
|
|
this.res.sendStatus = code => {
|
|
|
- this.AuthenticationManager.authenticate.callCount.should.equal(1)
|
|
|
- this.AuthenticationManager.authenticate
|
|
|
- .calledWith({ _id: this.user._id }, this.req.body.password)
|
|
|
- .should.equal(true)
|
|
|
+ this.AuthenticationManager.promises.authenticate.should.have.been
|
|
|
+ .calledOnce
|
|
|
+ this.AuthenticationManager.promises.authenticate.should.have.been.calledWith(
|
|
|
+ { _id: this.user._id },
|
|
|
+ this.req.body.password
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
this.UserController.tryDeleteUser(this.req, this.res, this.next)
|
|
|
@@ -184,8 +199,10 @@ describe('UserController', function () {
|
|
|
|
|
|
it('should delete the user', function (done) {
|
|
|
this.res.sendStatus = code => {
|
|
|
- this.UserDeleter.deleteUser.callCount.should.equal(1)
|
|
|
- this.UserDeleter.deleteUser.calledWith(this.user._id).should.equal(true)
|
|
|
+ this.UserDeleter.promises.deleteUser.should.have.been.calledOnce
|
|
|
+ this.UserDeleter.promises.deleteUser.should.have.been.calledWith(
|
|
|
+ this.user._id
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
this.UserController.tryDeleteUser(this.req, this.res, this.next)
|
|
|
@@ -207,9 +224,9 @@ describe('UserController', function () {
|
|
|
|
|
|
describe('when authenticate produces an error', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.AuthenticationManager.authenticate = sinon
|
|
|
- .stub()
|
|
|
- .callsArgWith(2, new Error('woops'))
|
|
|
+ this.AuthenticationManager.promises.authenticate.rejects(
|
|
|
+ new Error('woops')
|
|
|
+ )
|
|
|
})
|
|
|
|
|
|
it('should call next with an error', function (done) {
|
|
|
@@ -224,9 +241,7 @@ describe('UserController', function () {
|
|
|
|
|
|
describe('when authenticate does not produce a user', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.AuthenticationManager.authenticate = sinon
|
|
|
- .stub()
|
|
|
- .callsArgWith(2, null, null)
|
|
|
+ this.AuthenticationManager.promises.authenticate.resolves(null)
|
|
|
})
|
|
|
|
|
|
it('should return 403', function (done) {
|
|
|
@@ -240,7 +255,7 @@ describe('UserController', function () {
|
|
|
|
|
|
describe('when deleteUser produces an error', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.UserDeleter.deleteUser = sinon.stub().yields(new Error('woops'))
|
|
|
+ this.UserDeleter.promises.deleteUser.rejects(new Error('woops'))
|
|
|
})
|
|
|
|
|
|
it('should call next with an error', function (done) {
|
|
|
@@ -255,9 +270,9 @@ describe('UserController', function () {
|
|
|
|
|
|
describe('when deleteUser produces a known error', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.UserDeleter.deleteUser = sinon
|
|
|
- .stub()
|
|
|
- .yields(new Errors.SubscriptionAdminDeletionError())
|
|
|
+ this.UserDeleter.promises.deleteUser.rejects(
|
|
|
+ new Errors.SubscriptionAdminDeletionError()
|
|
|
+ )
|
|
|
})
|
|
|
|
|
|
it('should return a HTTP Unprocessable Entity error', function (done) {
|
|
|
@@ -298,9 +313,9 @@ describe('UserController', function () {
|
|
|
it('should send the user to subscribe', function (done) {
|
|
|
this.res.json = data => {
|
|
|
expect(data.message).to.equal('thanks_settings_updated')
|
|
|
- this.NewsLetterManager.subscribe
|
|
|
- .calledWith(this.user)
|
|
|
- .should.equal(true)
|
|
|
+ this.NewsLetterManager.promises.subscribe.should.have.been.calledWith(
|
|
|
+ this.user
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
this.UserController.subscribe(this.req, this.res)
|
|
|
@@ -311,12 +326,12 @@ describe('UserController', function () {
|
|
|
it('should send the user to unsubscribe', function (done) {
|
|
|
this.res.json = data => {
|
|
|
expect(data.message).to.equal('thanks_settings_updated')
|
|
|
- this.NewsLetterManager.unsubscribe
|
|
|
- .calledWith(this.user)
|
|
|
- .should.equal(true)
|
|
|
+ this.NewsLetterManager.promises.unsubscribe.should.have.been.calledWith(
|
|
|
+ this.user
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
- this.UserController.unsubscribe(this.req, this.res)
|
|
|
+ this.UserController.unsubscribe(this.req, this.res, this.next)
|
|
|
})
|
|
|
})
|
|
|
|
|
|
@@ -333,7 +348,7 @@ describe('UserController', function () {
|
|
|
this.user.save.called.should.equal(true)
|
|
|
done()
|
|
|
}
|
|
|
- this.UserController.updateUserSettings(this.req, this.res)
|
|
|
+ this.UserController.updateUserSettings(this.req, this.res, this.next)
|
|
|
})
|
|
|
|
|
|
it('should set the first name', function (done) {
|
|
|
@@ -401,12 +416,13 @@ describe('UserController', function () {
|
|
|
|
|
|
it('should call the user updater with the new email and user _id', function (done) {
|
|
|
this.req.body.email = this.newEmail.toUpperCase()
|
|
|
- this.UserUpdater.changeEmailAddress.callsArgWith(3)
|
|
|
this.res.sendStatus = code => {
|
|
|
code.should.equal(200)
|
|
|
- this.UserUpdater.changeEmailAddress
|
|
|
- .calledWith(this.user_id, this.newEmail, this.auditLog)
|
|
|
- .should.equal(true)
|
|
|
+ this.UserUpdater.promises.changeEmailAddress.should.have.been.calledWith(
|
|
|
+ this.user_id,
|
|
|
+ this.newEmail,
|
|
|
+ this.auditLog
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
this.UserController.updateUserSettings(this.req, this.res)
|
|
|
@@ -414,14 +430,15 @@ describe('UserController', function () {
|
|
|
|
|
|
it('should update the email on the session', function (done) {
|
|
|
this.req.body.email = this.newEmail.toUpperCase()
|
|
|
- this.UserUpdater.changeEmailAddress.callsArgWith(3)
|
|
|
let callcount = 0
|
|
|
- this.User.findById = (id, cb) => {
|
|
|
- if (++callcount === 2) {
|
|
|
- this.user.email = this.newEmail
|
|
|
- }
|
|
|
- cb(null, this.user)
|
|
|
- }
|
|
|
+ this.User.findById = id => ({
|
|
|
+ exec: async () => {
|
|
|
+ if (++callcount === 2) {
|
|
|
+ this.user.email = this.newEmail
|
|
|
+ }
|
|
|
+ return this.user
|
|
|
+ },
|
|
|
+ })
|
|
|
this.res.sendStatus = code => {
|
|
|
code.should.equal(200)
|
|
|
this.SessionManager.setInSessionUser
|
|
|
@@ -438,12 +455,11 @@ describe('UserController', function () {
|
|
|
|
|
|
it('should call populateTeamInvites', function (done) {
|
|
|
this.req.body.email = this.newEmail.toUpperCase()
|
|
|
- this.UserUpdater.changeEmailAddress.callsArgWith(3)
|
|
|
this.res.sendStatus = code => {
|
|
|
code.should.equal(200)
|
|
|
- this.UserHandler.populateTeamInvites
|
|
|
- .calledWith(this.user)
|
|
|
- .should.equal(true)
|
|
|
+ this.UserHandler.promises.populateTeamInvites.should.have.been.calledWith(
|
|
|
+ this.user
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
this.UserController.updateUserSettings(this.req, this.res)
|
|
|
@@ -452,7 +468,7 @@ describe('UserController', function () {
|
|
|
describe('when changeEmailAddress yields an error', function () {
|
|
|
it('should pass on an error and not send a success status', function (done) {
|
|
|
this.req.body.email = this.newEmail.toUpperCase()
|
|
|
- this.UserUpdater.changeEmailAddress.callsArgWith(3, new OError())
|
|
|
+ this.UserUpdater.promises.changeEmailAddress.rejects(new OError())
|
|
|
this.HttpErrorHandler.legacyInternal = sinon.spy(
|
|
|
(req, res, message, error) => {
|
|
|
expect(req).to.exist
|
|
|
@@ -473,8 +489,7 @@ describe('UserController', function () {
|
|
|
done()
|
|
|
})
|
|
|
this.req.body.email = this.newEmail.toUpperCase()
|
|
|
- this.UserUpdater.changeEmailAddress.callsArgWith(
|
|
|
- 3,
|
|
|
+ this.UserUpdater.promises.changeEmailAddress.rejects(
|
|
|
new Errors.EmailExistsError()
|
|
|
)
|
|
|
this.UserController.updateUserSettings(this.req, this.res)
|
|
|
@@ -483,7 +498,6 @@ describe('UserController', function () {
|
|
|
|
|
|
describe('when using an external auth source', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.UserUpdater.changeEmailAddress.callsArgWith(2)
|
|
|
this.newEmail = 'someone23@example.com'
|
|
|
this.req.externalAuthenticationSystemUsed = sinon.stub().returns(true)
|
|
|
})
|
|
|
@@ -492,7 +506,7 @@ describe('UserController', function () {
|
|
|
this.req.body.email = this.newEmail
|
|
|
this.res.sendStatus = code => {
|
|
|
code.should.equal(200)
|
|
|
- this.UserUpdater.changeEmailAddress
|
|
|
+ this.UserUpdater.promises.changeEmailAddress
|
|
|
.calledWith(this.user_id, this.newEmail)
|
|
|
.should.equal(false)
|
|
|
done()
|
|
|
@@ -504,7 +518,7 @@ describe('UserController', function () {
|
|
|
|
|
|
describe('logout', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.acceptsJson.returns(false)
|
|
|
+ this.RequestContentTypeDetection.acceptsJson.returns(false)
|
|
|
})
|
|
|
|
|
|
it('should destroy the session', function (done) {
|
|
|
@@ -522,10 +536,12 @@ describe('UserController', function () {
|
|
|
this.req.session.destroy = sinon.stub().callsArgWith(0)
|
|
|
this.res.redirect = url => {
|
|
|
url.should.equal('/login')
|
|
|
- this.UserSessionsManager.untrackSession.callCount.should.equal(1)
|
|
|
- this.UserSessionsManager.untrackSession
|
|
|
- .calledWith(sinon.match(this.req.user), this.req.sessionID)
|
|
|
- .should.equal(true)
|
|
|
+ this.UserSessionsManager.promises.untrackSession.should.have.been
|
|
|
+ .calledOnce
|
|
|
+ this.UserSessionsManager.promises.untrackSession.should.have.been.calledWith(
|
|
|
+ sinon.match(this.req.user),
|
|
|
+ this.req.sessionID
|
|
|
+ )
|
|
|
done()
|
|
|
}
|
|
|
|
|
|
@@ -562,7 +578,7 @@ describe('UserController', function () {
|
|
|
})
|
|
|
|
|
|
it('should send json with redir property for json request', function (done) {
|
|
|
- this.acceptsJson.returns(true)
|
|
|
+ this.RequestContentTypeDetection.acceptsJson.returns(true)
|
|
|
this.req.session.destroy = sinon.stub().callsArgWith(0)
|
|
|
this.res.status = code => {
|
|
|
code.should.equal(200)
|
|
|
@@ -580,9 +596,8 @@ describe('UserController', function () {
|
|
|
describe('success', function () {
|
|
|
it('should call revokeAllUserSessions', function (done) {
|
|
|
this.res.sendStatus.callsFake(() => {
|
|
|
- this.UserSessionsManager.promises.revokeAllUserSessions.callCount.should.equal(
|
|
|
- 1
|
|
|
- )
|
|
|
+ this.UserSessionsManager.promises.revokeAllUserSessions.should.have
|
|
|
+ .been.calledOnce
|
|
|
done()
|
|
|
})
|
|
|
this.UserController.clearSessions(this.req, this.res)
|
|
|
@@ -717,7 +732,7 @@ describe('UserController', function () {
|
|
|
actionDescribed: `your password has been changed on your account ${this.user.email}`,
|
|
|
action: 'password changed',
|
|
|
}
|
|
|
- const emailCall = this.EmailHandler.sendEmail.lastCall
|
|
|
+ const emailCall = this.EmailHandler.promises.sendEmail.lastCall
|
|
|
expect(emailCall.args[0]).to.equal('securityAlert')
|
|
|
expect(emailCall.args[1]).to.deep.equal(expectedArg)
|
|
|
done()
|
|
|
@@ -826,7 +841,7 @@ describe('UserController', function () {
|
|
|
newPassword1: 'newpass',
|
|
|
newPassword2: 'newpass',
|
|
|
}
|
|
|
- this.EmailHandler.sendEmail.yields(anError)
|
|
|
+ this.EmailHandler.promises.sendEmail.rejects(anError)
|
|
|
})
|
|
|
it('should not return error but should log it', function (done) {
|
|
|
this.res.json.callsFake(result => {
|