Просмотр исходного кода

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

add docs on UserHelper and tweak a few things

GitOrigin-RevId: 410be6b3cdf32cc72e14e26569f56369ce30c0a2
Jessica Lawshe 6 лет назад
Родитель
Сommit
1e8fc5337c

+ 64 - 38
services/web/test/acceptance/src/UserHelperTests.js

@@ -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('registerUser', function() {
-    describe('with no args', function() {
-      before(function() {
-        if (!Features.hasFeature('public-registration')) {
-          this.skip()
-        }
+    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('UserHelper.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())
@@ -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()

+ 83 - 14
services/web/test/acceptance/src/helpers/UserHelper.js

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