Merge pull request #2449 from overleaf/ew-user-helper-docs-and-tweaks

add docs on UserHelper and tweak a few things

GitOrigin-RevId: 410be6b3cdf32cc72e14e26569f56369ce30c0a2
This commit is contained in:
Jessica Lawshe 2019-12-16 10:35:08 -06:00 committed by Copybot
parent f2ad7ebfc3
commit 1e8fc5337c
2 changed files with 147 additions and 52 deletions

View file

@ -9,6 +9,13 @@ chai.should()
chai.use(chaiAsPromised)
describe('UserHelper', function() {
// Disable all tests unless the public-registration feature is enabled
beforeEach(function() {
if (!Features.hasFeature('public-registration')) {
this.skip()
}
})
describe('UserHelper.createUser', function() {
describe('with no args', function() {
it('should create new user with default username and password', async function() {
@ -51,7 +58,7 @@ describe('UserHelper', function() {
})
})
describe('fetching existing user', function() {
describe('UserHelper.getUser', function() {
let user
beforeEach(async function() {
@ -73,34 +80,50 @@ describe('UserHelper', function() {
})
})
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('UserHelper.loginUser', function() {
let userHelper
beforeEach(async function() {
userHelper = await UserHelper.createUser()
})
describe('with email and password', function() {
it('should login user', async function() {
const newUserHelper = await UserHelper.loginUser({
email: userHelper.getDefaultEmail(),
password: userHelper.getDefaultPassword()
})
newUserHelper.user.email.should.equal(userHelper.user.email)
})
})
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('without email', function() {
it('should throw error', async function() {
await UserHelper.loginUser({
password: userHelper.getDefaultPassword()
}).should.be.rejectedWith('email and password required')
})
})
describe('without password', function() {
it('should throw error', async function() {
await UserHelper.loginUser({
email: userHelper.getDefaultEmail()
}).should.be.rejectedWith('email and password required')
})
})
describe('without email and password', function() {
it('should throw error', async function() {
await UserHelper.loginUser().should.be.rejectedWith(
'email and password required'
)
})
})
})
describe('registerUser', function() {
describe('UserHelper.registerUser', function() {
describe('with no args', function() {
before(function() {
if (!Features.hasFeature('public-registration')) {
this.skip()
}
})
it('should create new user with default username and password', async function() {
const userHelper = await UserHelper.registerUser()
userHelper.user.email.should.equal(userHelper.getDefaultEmail())
@ -113,12 +136,6 @@ describe('UserHelper', function() {
})
describe('with email', function() {
before(function() {
if (!Features.hasFeature('public-registration')) {
this.skip()
}
})
it('should create new user with provided email and default password', async function() {
const userHelper = await UserHelper.registerUser({
email: 'foo2@test.com'
@ -133,12 +150,6 @@ describe('UserHelper', function() {
})
describe('with password', function() {
before(function() {
if (!Features.hasFeature('public-registration')) {
this.skip()
}
})
it('should create new user with provided password and default email', async function() {
const userHelper = await UserHelper.registerUser({
password: 'foofoofoo'
@ -153,13 +164,28 @@ describe('UserHelper', function() {
})
})
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 return cached csrfToken', async function() {
let userHelper = new UserHelper()
await userHelper.getCsrfToken()
const csrfToken = userHelper._csrfToken
await userHelper.getCsrfToken()
expect(csrfToken).to.equal(userHelper._csrfToken)
})
})
})
describe('after logout', function() {
let userHelper, oldCsrfToken
before(function() {
if (!Features.hasFeature('public-registration')) {
this.skip()
}
})
beforeEach(async function() {
userHelper = await UserHelper.registerUser()

View file

@ -6,7 +6,11 @@ const request = require('request-promise-native')
let globalUserNum = 1
module.exports = class UserHelper {
class UserHelper {
/**
* Create UserHelper
* @param {object} [user] - Mongo User object
*/
constructor(user = null) {
// used for constructing default emails, etc
this.userNum = globalUserNum++
@ -18,22 +22,41 @@ module.exports = class UserHelper {
/* sync functions */
/**
* Generate default email from unique (per instantiation) user number
* @returns {string} email
*/
getDefaultEmail() {
return `test.user.${this.userNum}@example.com`
}
/**
* Generate email, password args object. Default values will be used if
* email and password are not passed in args.
* @param {object} [userData]
* @param {string} [userData.email] email to use
* @param {string} [userData.password] password to use
* @returns {object} email, password object
*/
getDefaultEmailPassword(userData = {}) {
return {
email: this.getDefaultEmail(),
password: this.getDefaultPassword(this.userNum),
password: this.getDefaultPassword(),
...userData
}
}
/**
* Generate default password from unique (per instantiation) user number
* @returns {string} password
*/
getDefaultPassword() {
return `new-password-${this.userNum}!`
return `New-Password-${this.userNum}!`
}
/**
* (Re)set internal state of UserHelper object.
*/
reset() {
// cached csrf token
this._csrfToken = ''
@ -44,22 +67,27 @@ module.exports = class UserHelper {
// create new request instance
this.request = request.defaults({})
// initialize request instance with default options
this.setRequestDefaults()
}
setRequestDefaults(defaults = {}) {
// request-promise instance for making requests
this.request = this.request.defaults({
this.setRequestDefaults({
baseUrl: UserHelper.baseUrl(),
followRedirect: false,
jar: this.jar,
resolveWithFullResponse: true,
...defaults
resolveWithFullResponse: true
})
}
/* Set defaults for request object. Applied over existing defaults.
* @param {object} [defaults]
*/
setRequestDefaults(defaults = {}) {
// request-promise instance for making requests
this.request = this.request.defaults(defaults)
}
/* async http api call methods */
/**
* Requests csrf token unless already cached in internal state
*/
async getCsrfToken() {
if (this._csrfToken) {
return
@ -73,6 +101,11 @@ module.exports = class UserHelper {
})
}
/**
* Make request to POST /logout
* @param {object} [options] options to pass to request
* @returns {object} http response
*/
async logout(options = {}) {
// do not throw exception on 302
options.simple = false
@ -84,20 +117,30 @@ module.exports = class UserHelper {
) {
throw new Error('logout failed')
}
// clear out internal state
this.reset()
// after logout CSRF token becomes invalid
this._csrfToken = ''
// resolve with http request response
return response
}
/* static sync methods */
/**
* Generates base URL from env options
* @returns {string} baseUrl
*/
static baseUrl() {
return `http://${process.env['HTTP_TEST_HOST'] || 'localhost'}:3000`
}
/* static async instantiation methods */
/**
* Create a new user via UserCreator and return UserHelper instance
* @param {object} attributes user data for UserCreator
* @param {object} options options for UserCreator
* @returns {UserHelper}
*/
static async createUser(attributes = {}, options = {}) {
const userHelper = new UserHelper()
attributes = userHelper.getDefaultEmailPassword(attributes)
@ -122,14 +165,30 @@ module.exports = class UserHelper {
return userHelper
}
/**
* Get existing user via UserGetter and return UserHelper instance.
* All args passed to UserGetter.getUser.
* @returns {UserHelper}
*/
static async getUser(...args) {
const user = await UserGetter.promises.getUser(...args)
if (!user) {
throw new Error(`no user found for args: ${JSON.stringify([...args])}`)
}
return new UserHelper(user)
}
/**
* Login to existing account via request and return UserHelper instance
* @param {object} userData
* @param {string} userData.email
* @param {string} userData.password
* @returns {UserHelper}
*/
static async loginUser(userData) {
if (!userData.email || !userData.password) {
if (!userData || !userData.email || !userData.password) {
throw new Error('email and password required')
}
const userHelper = new UserHelper()
@ -153,6 +212,14 @@ module.exports = class UserHelper {
return userHelper
}
/**
* Register new account via request and return UserHelper instance.
* If userData is not provided the default email and password will be used.
* @param {object} [userData]
* @param {string} [userData.email]
* @param {string} [userData.password]
* @returns {UserHelper}
*/
static async registerUser(userData, options = {}) {
const userHelper = new UserHelper()
await userHelper.getCsrfToken()
@ -177,3 +244,5 @@ module.exports = class UserHelper {
return userHelper
}
}
module.exports = UserHelper