new UserHelper class for acceptance tests

GitOrigin-RevId: 194593b8b70c74d2771f8e6f695faa47c84beeca
This commit is contained in:
Ersun Warncke 2019-09-27 08:31:44 -04:00 committed by sharelatex
parent 61d895c8fc
commit 3a7384c83f
3 changed files with 308 additions and 2 deletions

View file

@ -1,4 +1,3 @@
let AuthenticationManager
const Settings = require('settings-sharelatex')
const { User } = require('../../models/User')
const { db, ObjectId } = require('../../infrastructure/mongojs')
@ -9,6 +8,7 @@ const {
InvalidEmailError,
InvalidPasswordError
} = require('./AuthenticationErrors')
const util = require('util')
const BCRYPT_ROUNDS = Settings.security.bcryptRounds || 12
const BCRYPT_MINOR_VERSION = Settings.security.bcryptMinorVersion || 'a'
@ -22,7 +22,7 @@ const _checkWriteResult = function(result, callback) {
}
}
module.exports = AuthenticationManager = {
const AuthenticationManager = {
authenticate(query, password, callback) {
// Using Mongoose for legacy reasons here. The returned User instance
// gets serialized into the session and there may be subtle differences
@ -217,3 +217,10 @@ module.exports = AuthenticationManager = {
return true
}
}
AuthenticationManager.promises = {
authenticate: util.promisify(AuthenticationManager.authenticate),
hashPassword: util.promisify(AuthenticationManager.hashPassword)
}
module.exports = AuthenticationManager

View file

@ -0,0 +1,153 @@
const AuthenticationManager = require('../../../app/src/Features/Authentication/AuthenticationManager')
const UserHelper = require('./helpers/UserHelper')
const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')
const expect = chai.expect
chai.should()
chai.use(chaiAsPromised)
describe('UserHelper', function() {
describe('UserHelper.createUser', function() {
describe('with no args', function() {
it('should create new user with default username and password', async function() {
const userHelper = await UserHelper.createUser()
userHelper.user.email.should.equal(userHelper.getDefaultEmail())
const authedUser = await AuthenticationManager.promises.authenticate(
{ _id: userHelper.user._id },
userHelper.getDefaultPassword()
)
expect(authedUser).to.not.be.null
})
})
describe('with email', function() {
it('should create new user with provided email and default password', async function() {
const userHelper = await UserHelper.createUser({
email: 'foo@test.com'
})
userHelper.user.email.should.equal('foo@test.com')
const authedUser = await AuthenticationManager.promises.authenticate(
{ _id: userHelper.user._id },
userHelper.getDefaultPassword()
)
expect(authedUser).to.not.be.null
})
})
describe('with password', function() {
it('should create new user with provided password and default email', async function() {
const userHelper = await UserHelper.createUser({
password: 'foofoofoo'
})
userHelper.user.email.should.equal(userHelper.getDefaultEmail())
const authedUser = await AuthenticationManager.promises.authenticate(
{ _id: userHelper.user._id },
'foofoofoo'
)
expect(authedUser).to.not.be.null
})
})
})
describe('fetching existing user', function() {
let user
beforeEach(async function() {
user = (await UserHelper.createUser()).user
})
describe('with string id', function() {
it('should fetch user', async function() {
const userHelper = await UserHelper.getUser(user._id.toString())
userHelper.user.email.should.equal(user.email)
})
})
describe('with _id', function() {
it('should fetch user', async function() {
const userHelper = await UserHelper.getUser({ _id: user._id })
userHelper.user.email.should.equal(user.email)
})
})
})
describe('getCsrfToken', function() {
describe('when the csrfToken is not cached', function() {
it('should fetch csrfToken', async function() {
const userHelper = new UserHelper()
await userHelper.getCsrfToken()
expect(userHelper.csrfToken).to.be.a.string
})
})
describe('when the csrfToken is cached', function() {
it('should fetch csrfToken', async function() {
let userHelper = new UserHelper()
await userHelper.getCsrfToken()
const csrfToken = userHelper._csrfToken
await userHelper.getCsrfToken()
expect(csrfToken).to.equal(userHelper._csrfToken)
})
})
})
describe('registerUser', function() {
describe('with no args', function() {
it('should create new user with default username and password', async function() {
const userHelper = await UserHelper.registerUser()
userHelper.user.email.should.equal(userHelper.getDefaultEmail())
const authedUser = await AuthenticationManager.promises.authenticate(
{ _id: userHelper.user._id },
userHelper.getDefaultPassword()
)
expect(authedUser).to.not.be.null
})
})
describe('with email', function() {
it('should create new user with provided email and default password', async function() {
const userHelper = await UserHelper.registerUser({
email: 'foo2@test.com'
})
userHelper.user.email.should.equal('foo2@test.com')
const authedUser = await AuthenticationManager.promises.authenticate(
{ _id: userHelper.user._id },
userHelper.getDefaultPassword()
)
expect(authedUser).to.not.be.null
})
})
describe('with password', function() {
it('should create new user with provided password and default email', async function() {
const userHelper = await UserHelper.registerUser({
password: 'foofoofoo'
})
userHelper.user.email.should.equal(userHelper.getDefaultEmail())
const authedUser = await AuthenticationManager.promises.authenticate(
{ _id: userHelper.user._id },
'foofoofoo'
)
expect(authedUser).to.not.be.null
})
})
})
describe('after logout', function() {
let userHelper, oldCsrfToken
beforeEach(async function() {
userHelper = await UserHelper.registerUser()
oldCsrfToken = userHelper.csrfToken
})
it('refreshes csrf token after logout', async function() {
await userHelper.logout()
expect(userHelper._csrfToken).to.equal('')
await userHelper.getCsrfToken()
expect(userHelper._csrfToken).to.not.equal('')
expect(userHelper._csrfToken).to.not.equal(oldCsrfToken)
})
})
})

View file

@ -0,0 +1,146 @@
const AuthenticationManager = require('../../../../app/src/Features/Authentication/AuthenticationManager')
const UserCreator = require('../../../../app/src/Features/User/UserCreator')
const UserGetter = require('../../../../app/src/Features/User/UserGetter')
const request = require('request-promise-native')
let globalUserNum = 1
module.exports = class UserHelper {
constructor(user = null) {
// used for constructing default emails, etc
this.userNum = globalUserNum++
// initialize all internal state properties to defaults
this.reset()
// set user if passed in, may be null
this.user = user
}
/* sync functions */
getDefaultEmail() {
return `test.user.${this.userNum}@example.com`
}
getDefaultEmailPassword(userData = {}) {
return {
email: this.getDefaultEmail(),
password: this.getDefaultPassword(this.userNum),
...userData
}
}
getDefaultPassword() {
return `new-password-${this.userNum}!`
}
reset() {
// cached csrf token
this._csrfToken = ''
// used to store mongo user object once created/loaded
this.user = null
// cookie jar
this.jar = request.jar()
// initialize request instance with default options
this.setRequestDefaults()
}
setRequestDefaults(defaults = {}) {
// request-promise instance for making requests
this.request = request.defaults({
baseUrl: UserHelper.baseUrl(),
followRedirect: false,
jar: this.jar,
resolveWithFullResponse: true,
...defaults
})
}
/* async http api call methods */
async getCsrfToken() {
if (this._csrfToken) {
return
}
// get csrf token from api and store
const response = await this.request.get('/dev/csrf')
this._csrfToken = response.body
// use csrf token for requests
this.setRequestDefaults({
headers: { 'x-csrf-token': this._csrfToken }
})
}
async logout(options = {}) {
// do not throw exception on 302
options.simple = false
// post logout
const response = await this.request.post('/logout', options)
if (
response.statusCode !== 302 ||
!response.headers.location.includes('/login')
) {
throw new Error('logout failed')
}
// clear out internal state
this.reset()
// resolve with http request response
return response
}
/* static sync methods */
static baseUrl() {
return `http://${process.env['HTTP_TEST_HOST'] || 'localhost'}:3000`
}
/* static async instantiation methods */
static async createUser(attributes = {}, options = {}) {
const userHelper = new UserHelper()
attributes = userHelper.getDefaultEmailPassword(attributes)
// skip creating affiliations by default because it requires an
// API call that will usually not be mocked in testing env
if (attributes.skip_affiliation !== false) {
attributes.skip_affiliation = true
}
// hash password and delete plaintext if set
if (attributes.password) {
attributes.hashedPassword = await AuthenticationManager.promises.hashPassword(
attributes.password
)
delete attributes.password
}
userHelper.user = await UserCreator.promises.createNewUser(
attributes,
options
)
return userHelper
}
static async getUser(...args) {
const user = await UserGetter.promises.getUser(...args)
return new UserHelper(user)
}
static async registerUser(userData, options = {}) {
const userHelper = new UserHelper()
await userHelper.getCsrfToken()
userData = userHelper.getDefaultEmailPassword(userData)
options.json = userData
const { body } = await userHelper.request.post('/register', options)
if (body.message && body.message.type === 'error') {
throw new Error(`register api error: ${body.message.text}`)
}
userHelper.user = await UserGetter.promises.getUser({
email: userData.email
})
if (!userHelper.user) {
throw new Error(`user not found for email: ${userData.email}`)
}
return userHelper
}
}