Эх сурвалжийг харах

Merge pull request #16002 from overleaf/jpa-real-time-auto-join-tests

[real-time] migrate acceptance tests to auto-join

GitOrigin-RevId: fc14a4e803bfab4d07f2773c6ecbdb5459d12684
Jakob Ackermann 2 жил өмнө
parent
commit
5520f9eed9

+ 6 - 60
services/real-time/test/acceptance/js/ApplyUpdateTests.js

@@ -87,16 +87,7 @@ describe('applyOtUpdate', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -206,21 +197,12 @@ describe('applyOtUpdate', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            this.client.on('connectionAccepted', cb)
+            this.client = RealTimeClient.connect(this.project_id, cb)
             return this.client.on('otUpdateError', otUpdateError => {
               this.otUpdateError = otUpdateError
             })
           },
 
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
-          },
-
           cb => {
             return this.client.emit('joinDoc', this.doc_id, cb)
           },
@@ -303,16 +285,7 @@ describe('applyOtUpdate', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -393,16 +366,7 @@ describe('applyOtUpdate', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -506,16 +470,7 @@ describe('applyOtUpdate', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -593,16 +548,7 @@ describe('applyOtUpdate', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {

+ 7 - 48
services/real-time/test/acceptance/js/ClientTrackingTests.js

@@ -50,39 +50,17 @@ describe('clientTracking', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
+            this.clientA = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
-            this.clientB = RealTimeClient.connect()
-            return this.clientB.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              {
-                project_id: this.project_id,
-              },
-              cb
-            )
+            this.clientB = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
             return this.clientA.emit('joinDoc', this.doc_id, cb)
           },
 
-          cb => {
-            return this.clientB.emit(
-              'joinProject',
-              {
-                project_id: this.project_id,
-              },
-              cb
-            )
-          },
-
           cb => {
             this.updates = []
             this.clientB.on('clientTracking.clientUpdated', data => {
@@ -179,38 +157,19 @@ describe('clientTracking', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
+            this.clientA = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
-            return this.clientA.emit(
-              'joinProject',
-              {
-                project_id: this.project_id,
-              },
+            RealTimeClient.setAnonSession(
+              this.project_id,
+              this.anonymousAccessToken,
               cb
             )
           },
 
           cb => {
-            return RealTimeClient.setSession({}, cb)
-          },
-
-          cb => {
-            this.anonymous = RealTimeClient.connect()
-            return this.anonymous.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.anonymous.emit(
-              'joinProject',
-              {
-                project_id: this.project_id,
-                anonymousAccessToken: this.anonymousAccessToken,
-              },
-              cb
-            )
+            this.anonymous = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {

+ 2 - 20
services/real-time/test/acceptance/js/DrainManagerTests.js

@@ -63,29 +63,11 @@ describe('DrainManagerTests', function () {
       return async.series(
         [
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
+            this.clientA = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
-            this.clientB = RealTimeClient.connect()
-            return this.clientB.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
-          },
-
-          cb => {
-            return this.clientB.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.clientB = RealTimeClient.connect(this.project_id, cb)
           },
         ],
         done

+ 10 - 32
services/real-time/test/acceptance/js/EarlyDisconnect.js

@@ -31,10 +31,9 @@ describe('EarlyDisconnect', function () {
   describe('when the client disconnects before joinProject completes', function () {
     before(function () {
       // slow down web-api requests to force the race condition
-      let joinProject
-      this.actualWebAPIjoinProject = joinProject = MockWebServer.joinProject
-      return (MockWebServer.joinProject = (projectId, userId, cb) =>
-        setTimeout(() => joinProject(projectId, userId, cb), 300))
+      this.actualWebAPIjoinProject = MockWebServer.joinProject
+      MockWebServer.joinProject = (...args) =>
+        setTimeout(() => this.actualWebAPIjoinProject(...args), 300)
     })
 
     after(function () {
@@ -61,19 +60,10 @@ describe('EarlyDisconnect', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              () => {}
-            )
-            // disconnect before joinProject completes
+            this.clientA = RealTimeClient.connect(this.project_id, cb)
+            // disconnect after the handshake and before joinProject completes
+            setTimeout(() => this.clientA.disconnect(), 100)
             this.clientA.on('disconnect', () => cb())
-            return this.clientA.disconnect()
           },
 
           cb => {
@@ -122,14 +112,8 @@ describe('EarlyDisconnect', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel
@@ -210,14 +194,8 @@ describe('EarlyDisconnect', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel

+ 1 - 10
services/real-time/test/acceptance/js/HttpControllerTests.js

@@ -63,16 +63,7 @@ describe('HttpControllerTests', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {

+ 7 - 70
services/real-time/test/acceptance/js/JoinDocTests.js

@@ -59,16 +59,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -147,16 +138,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -235,16 +217,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -327,16 +300,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -413,16 +377,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -503,16 +458,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
@@ -594,16 +540,7 @@ describe('joinDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {

+ 53 - 303
services/real-time/test/acceptance/js/JoinProjectTests.js

@@ -36,14 +36,8 @@ describe('joinProject', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.client = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel
@@ -143,21 +137,16 @@ describe('joinProject', function () {
           },
 
           cb => {
-            RealTimeClient.setSession({}, cb)
-          },
-
-          cb => {
-            this.client = RealTimeClient.connect()
-            this.client.on('connectionAccepted', cb)
+            RealTimeClient.setAnonSession(
+              this.project_id,
+              this.anonymousAccessToken,
+              cb
+            )
           },
 
           cb => {
-            this.client.emit(
-              'joinProject',
-              {
-                project_id: this.project_id,
-                anonymousAccessToken: this.anonymousAccessToken,
-              },
+            this.client = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel
@@ -246,14 +235,8 @@ describe('joinProject', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.client = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.error = error
                 this.project = project
@@ -275,11 +258,8 @@ describe('joinProject', function () {
     return it('should not have joined the project room', function (done) {
       return RealTimeClient.getConnectedClient(
         this.client.socket.sessionid,
-        (error, client) => {
-          if (error) return done(error)
-          expect(Array.from(client.rooms).includes(this.project_id)).to.equal(
-            false
-          )
+        error => {
+          expect(error.message).to.equal('not found')
           return done()
         }
       )
@@ -308,22 +288,10 @@ describe('joinProject', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              (error, project, privilegeLevel, protocolVersion) => {
-                this.error = error
-                this.project = project
-                this.privilegeLevel = privilegeLevel
-                this.protocolVersion = protocolVersion
-                cb()
-              }
-            )
+            this.client = RealTimeClient.connect(this.project_id, error => {
+              this.error = error
+              cb()
+            })
           },
         ],
         done
@@ -335,16 +303,10 @@ describe('joinProject', function () {
     })
 
     it('should not have joined the project room', function (done) {
-      RealTimeClient.getConnectedClient(
-        this.client.socket.sessionid,
-        (error, client) => {
-          if (error) return done(error)
-          expect(Array.from(client.rooms).includes(this.project_id)).to.equal(
-            false
-          )
-          done()
-        }
-      )
+      RealTimeClient.getConnectedClient(this.client.socket.sessionid, error => {
+        expect(error.message).to.equal('not found')
+        done()
+      })
     })
   })
 
@@ -370,22 +332,10 @@ describe('joinProject', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              (error, project, privilegeLevel, protocolVersion) => {
-                this.error = error
-                this.project = project
-                this.privilegeLevel = privilegeLevel
-                this.protocolVersion = protocolVersion
-                cb()
-              }
-            )
+            this.client = RealTimeClient.connect(this.project_id, error => {
+              this.error = error
+              cb()
+            })
           },
         ],
         done
@@ -397,16 +347,10 @@ describe('joinProject', function () {
     })
 
     it('should not have joined the project room', function (done) {
-      RealTimeClient.getConnectedClient(
-        this.client.socket.sessionid,
-        (error, client) => {
-          if (error) return done(error)
-          expect(Array.from(client.rooms).includes(this.project_id)).to.equal(
-            false
-          )
-          done()
-        }
-      )
+      RealTimeClient.getConnectedClient(this.client.socket.sessionid, error => {
+        expect(error.message).to.equal('not found')
+        done()
+      })
     })
   })
 
@@ -416,19 +360,10 @@ describe('joinProject', function () {
       return async.series(
         [
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: 'invalid-id' },
-              error => {
-                this.error = error
-                return cb()
-              }
-            )
+            this.client = RealTimeClient.connect('invalid-id', error => {
+              this.error = error
+              return cb()
+            })
           },
         ],
         done
@@ -444,94 +379,13 @@ describe('joinProject', function () {
     })
   })
 
-  describe('when joining more than one project', function () {
-    before(function (done) {
-      return async.series(
-        [
-          cb => {
-            return FixturesManager.setUpProject(
-              {
-                privilegeLevel: 'owner',
-                project: {
-                  name: 'Other Project',
-                },
-              },
-              (e, { project_id: projectId, user_id: userId }) => {
-                this.other_project_id = projectId
-                this.other_user_id = userId
-                return cb(e)
-              }
-            )
-          },
-
-          cb => {
-            return FixturesManager.setUpProject(
-              {
-                user_id: this.other_user_id,
-                privilegeLevel: 'owner',
-                project: {
-                  name: 'Test Project',
-                },
-              },
-              (e, { project_id: projectId, user_id: userId }) => {
-                this.project_id = projectId
-                this.user_id = userId
-                return cb(e)
-              }
-            )
-          },
-
-          cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              (error, project, privilegeLevel, protocolVersion) => {
-                this.project = project
-                this.privilegeLevel = privilegeLevel
-                this.protocolVersion = protocolVersion
-                return cb(error)
-              }
-            )
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.other_project_id },
-              error => {
-                this.error = error
-                return cb()
-              }
-            )
-          },
-        ],
-        done
-      )
-    })
-
-    return it('should return an error', function () {
-      this.error.message.should.equal('cannot join multiple projects')
-    })
-  })
-
   describe('when over rate limit', function () {
     before(function (done) {
       return async.series(
         [
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: '429429429429429429429429' }, // rate-limited
+            this.client = RealTimeClient.connect(
+              '429429429429429429429429', // rate-limited
               error => {
                 this.error = error
                 return cb()
@@ -551,7 +405,6 @@ describe('joinProject', function () {
 
   describe('when automatically joining the project', function () {
     describe('when authorized', function () {
-      let connectionAcceptedReceived = false
       before(function (done) {
         async.series(
           [
@@ -573,19 +426,12 @@ describe('joinProject', function () {
 
             cb => {
               this.client = RealTimeClient.connect(
-                `projectId=${this.project_id}`
-              )
-              this.client.on('connectionAccepted', () => {
-                connectionAcceptedReceived = true
-              })
-              this.client.on('connectionRejected', cb)
-              this.client.on(
-                'joinProjectResponse',
-                ({ project, permissionsLevel, protocolVersion }) => {
+                this.project_id,
+                (err, project, permissionsLevel, protocolVersion) => {
                   this.project = project
                   this.permissionsLevel = permissionsLevel
                   this.protocolVersion = protocolVersion
-                  cb()
+                  cb(err)
                 }
               )
             },
@@ -594,10 +440,6 @@ describe('joinProject', function () {
         )
       })
 
-      it('should not emit connectionAccepted', function () {
-        expect(connectionAcceptedReceived).to.equal(false)
-      })
-
       it('should get the project from web', function () {
         MockWebServer.joinProject
           .calledWith(this.project_id, this.user_id)
@@ -652,7 +494,6 @@ describe('joinProject', function () {
     })
 
     describe('when authorized with token', function () {
-      let connectionAcceptedReceived = false
       before(function (done) {
         async.series(
           [
@@ -682,31 +523,21 @@ describe('joinProject', function () {
             },
 
             cb => {
-              RealTimeClient.setSession(
-                {
-                  anonTokenAccess: {
-                    [this.project_id]: this.anonymousAccessToken,
-                  },
-                },
+              RealTimeClient.setAnonSession(
+                this.project_id,
+                this.anonymousAccessToken,
                 cb
               )
             },
 
             cb => {
               this.client = RealTimeClient.connect(
-                `projectId=${this.project_id}`
-              )
-              this.client.on('connectionAccepted', () => {
-                connectionAcceptedReceived = true
-              })
-              this.client.on('connectionRejected', cb)
-              this.client.on(
-                'joinProjectResponse',
-                ({ project, permissionsLevel, protocolVersion }) => {
+                this.project_id,
+                (err, project, permissionsLevel, protocolVersion) => {
                   this.project = project
                   this.permissionsLevel = permissionsLevel
                   this.protocolVersion = protocolVersion
-                  cb()
+                  cb(err)
                 }
               )
             },
@@ -715,10 +546,6 @@ describe('joinProject', function () {
         )
       })
 
-      it('should not emit connectionAccepted', function () {
-        expect(connectionAcceptedReceived).to.equal(false)
-      })
-
       it('should get the project from web', function () {
         MockWebServer.joinProject
           .calledWith(
@@ -795,10 +622,7 @@ describe('joinProject', function () {
             },
 
             cb => {
-              this.client = RealTimeClient.connect(
-                `projectId=${this.project_id}`
-              )
-              this.client.on('connectionRejected', err => {
+              this.client = RealTimeClient.connect(this.project_id, err => {
                 this.error = err
                 cb()
               })
@@ -858,10 +682,7 @@ describe('joinProject', function () {
             },
 
             cb => {
-              this.client = RealTimeClient.connect(
-                `projectId=${this.project_id}`
-              )
-              this.client.on('connectionRejected', err => {
+              this.client = RealTimeClient.connect(this.project_id, err => {
                 this.error = err
                 cb()
               })
@@ -921,10 +742,7 @@ describe('joinProject', function () {
             },
 
             cb => {
-              this.client = RealTimeClient.connect(
-                `projectId=${this.project_id}`
-              )
-              this.client.on('connectionRejected', err => {
+              this.client = RealTimeClient.connect(this.project_id, err => {
                 this.error = err
                 cb()
               })
@@ -968,8 +786,7 @@ describe('joinProject', function () {
         async.series(
           [
             cb => {
-              this.client = RealTimeClient.connect('projectId=invalid-id')
-              this.client.on('connectionRejected', err => {
+              this.client = RealTimeClient.connect('invalid-id', err => {
                 this.error = err
                 cb()
               })
@@ -1000,73 +817,6 @@ describe('joinProject', function () {
       })
     })
 
-    describe('when joining more than one project', function () {
-      before(function (done) {
-        async.series(
-          [
-            cb => {
-              FixturesManager.setUpProject(
-                {
-                  privilegeLevel: 'owner',
-                  project: {
-                    name: 'Other Project',
-                  },
-                },
-                (e, { project_id: projectId, user_id: userId }) => {
-                  this.other_project_id = projectId
-                  this.other_user_id = userId
-                  cb(e)
-                }
-              )
-            },
-
-            cb => {
-              FixturesManager.setUpProject(
-                {
-                  user_id: this.other_user_id,
-                  privilegeLevel: 'owner',
-                  project: {
-                    name: 'Test Project',
-                  },
-                },
-                (e, { project_id: projectId, user_id: userId }) => {
-                  this.project_id = projectId
-                  this.user_id = userId
-                  cb(e)
-                }
-              )
-            },
-
-            cb => {
-              this.client = RealTimeClient.connect(
-                `projectId=${this.project_id}`
-              )
-              this.client.on('connectionRejected', cb)
-              this.client.on('joinProjectResponse', () => {
-                cb()
-              })
-            },
-
-            cb => {
-              this.client.emit(
-                'joinProject',
-                { project_id: this.other_project_id },
-                error => {
-                  this.error = error
-                  cb()
-                }
-              )
-            },
-          ],
-          done
-        )
-      })
-
-      it('should return an error', function () {
-        this.error.message.should.equal('cannot join multiple projects')
-      })
-    })
-
     describe('when over rate limit', function () {
       let joinProjectResponseReceived = false
       before(function (done) {
@@ -1074,12 +824,12 @@ describe('joinProject', function () {
           [
             cb => {
               this.client = RealTimeClient.connect(
-                'projectId=429429429429429429429429'
+                '429429429429429429429429',
+                err => {
+                  this.error = err
+                  cb()
+                }
               )
-              this.client.on('connectionRejected', err => {
-                this.error = err
-                cb()
-              })
               this.client.on('joinProjectResponse', () => {
                 joinProjectResponseReceived = true
                 cb()

+ 1 - 10
services/real-time/test/acceptance/js/LeaveDocTests.js

@@ -67,16 +67,7 @@ describe('leaveDoc', function () {
           },
 
           cb => {
-            this.client = RealTimeClient.connect()
-            return this.client.on('connectionAccepted', cb)
-          },
-
-          cb => {
-            return this.client.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              cb
-            )
+            this.client = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {

+ 4 - 38
services/real-time/test/acceptance/js/LeaveProjectTests.js

@@ -45,13 +45,11 @@ describe('leaveProject', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connectionAccepted', cb)
+            this.clientA = RealTimeClient.connect(this.project_id, cb)
           },
 
           cb => {
-            this.clientB = RealTimeClient.connect()
-            this.clientB.on('connectionAccepted', cb)
+            this.clientB = RealTimeClient.connect(this.project_id, cb)
 
             this.clientBDisconnectMessages = []
             return this.clientB.on(
@@ -62,32 +60,6 @@ describe('leaveProject', function () {
             )
           },
 
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              (error, project, privilegeLevel, protocolVersion) => {
-                this.project = project
-                this.privilegeLevel = privilegeLevel
-                this.protocolVersion = protocolVersion
-                return cb(error)
-              }
-            )
-          },
-
-          cb => {
-            return this.clientB.emit(
-              'joinProject',
-              { project_id: this.project_id },
-              (error, project, privilegeLevel, protocolVersion) => {
-                this.project = project
-                this.privilegeLevel = privilegeLevel
-                this.protocolVersion = protocolVersion
-                return cb(error)
-              }
-            )
-          },
-
           cb => {
             return FixturesManager.setUpDoc(
               this.project_id,
@@ -192,14 +164,8 @@ describe('leaveProject', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connect', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel

+ 52 - 88
services/real-time/test/acceptance/js/MatrixTests.js

@@ -79,16 +79,9 @@ describe('MatrixTests', function () {
         if (err) return done(err)
         privateProjectId = projectId
         privateDocId = docId
-        privateClient = RealTimeClient.connect()
-        privateClient.on('connectionAccepted', () => {
-          privateClient.emit(
-            'joinProject',
-            { project_id: privateProjectId },
-            err => {
-              if (err) return done(err)
-              privateClient.emit('joinDoc', privateDocId, done)
-            }
-          )
+        privateClient = RealTimeClient.connect(projectId, err => {
+          if (err) return done(err)
+          privateClient.emit('joinDoc', privateDocId, done)
         })
       }
     )
@@ -110,28 +103,19 @@ describe('MatrixTests', function () {
 
   const USER_SETUP = {
     anonymous: {
-      getAnonymousAccessToken() {
-        return readWriteAnonymousAccessToken
-      },
       setup(cb) {
-        RealTimeClient.setSession(
-          {
-            anonTokenAccess: {
-              [readWriteProjectId]: readWriteAnonymousAccessToken,
-            },
-          },
+        RealTimeClient.setAnonSession(
+          readWriteProjectId,
+          readWriteAnonymousAccessToken,
           err => {
             if (err) return cb(err)
-            cb(null, {
-              client: RealTimeClient.connect(),
-            })
+            cb(null, {})
           }
         )
       },
     },
 
     registered: {
-      getAnonymousAccessToken() {},
       setup(cb) {
         const userId = FixturesManager.getRandomId()
         const user = { _id: userId, first_name: 'Joe', last_name: 'Bloggs' }
@@ -145,14 +129,12 @@ describe('MatrixTests', function () {
           )
           cb(null, {
             user_id: userId,
-            client: RealTimeClient.connect(),
           })
         })
       },
     },
 
     registeredWithOwnedProject: {
-      getAnonymousAccessToken() {},
       setup(cb) {
         FixturesManager.setUpEditorSession(
           { privilegeLevel: 'owner' },
@@ -168,7 +150,6 @@ describe('MatrixTests', function () {
               user_id: userId,
               project_id: projectId,
               doc_id: docId,
-              client: RealTimeClient.connect(),
             })
           }
         )
@@ -182,34 +163,17 @@ describe('MatrixTests', function () {
     let options, client
 
     const SESSION_SETUP = {
-      noop: {
-        getActions(cb) {
-          cb(null, [])
-        },
-        needsOwnProject: false,
-      },
-
       joinReadWriteProject: {
         getActions(cb) {
-          const anonymousAccessToken = userItem.getAnonymousAccessToken()
-          cb(null, [
-            {
-              rpc: 'joinProject',
-              args: [{ project_id: readWriteProjectId, anonymousAccessToken }],
-            },
-          ])
+          cb(null, [{ connect: readWriteProjectId }])
         },
         needsOwnProject: false,
       },
 
       joinReadWriteProjectAndDoc: {
         getActions(cb) {
-          const anonymousAccessToken = userItem.getAnonymousAccessToken()
           cb(null, [
-            {
-              rpc: 'joinProject',
-              args: [{ project_id: readWriteProjectId, anonymousAccessToken }],
-            },
+            { connect: readWriteProjectId },
             { rpc: 'joinDoc', args: [readWriteDocId] },
           ])
         },
@@ -218,25 +182,15 @@ describe('MatrixTests', function () {
 
       joinOwnProject: {
         getActions(cb) {
-          const anonymousAccessToken = userItem.getAnonymousAccessToken()
-          cb(null, [
-            {
-              rpc: 'joinProject',
-              args: [{ project_id: options.project_id, anonymousAccessToken }],
-            },
-          ])
+          cb(null, [{ connect: options.project_id }])
         },
         needsOwnProject: true,
       },
 
       joinOwnProjectAndDoc: {
         getActions(cb) {
-          const anonymousAccessToken = userItem.getAnonymousAccessToken()
           cb(null, [
-            {
-              rpc: 'joinProject',
-              args: [{ project_id: options.project_id, anonymousAccessToken }],
-            },
+            { connect: options.project_id },
             { rpc: 'joinDoc', args: [options.doc_id] },
           ])
         },
@@ -250,19 +204,27 @@ describe('MatrixTests', function () {
 
         async.eachSeries(
           actions,
-          (action, cb) => {
-            if (action.rpc) {
-              client.emit(action.rpc, ...action.args, (...returnedArgs) => {
-                const error = returnedArgs.shift()
-                if (action.fails) {
-                  expect(error).to.exist
-                  expect(returnedArgs).to.have.length(0)
-                  return cb()
-                }
-                cb(error)
-              })
+          (action, next) => {
+            const cb = (...returnedArgs) => {
+              const error = returnedArgs.shift()
+              if (action.fails) {
+                expect(error).to.exist
+                expect(returnedArgs).to.have.length(0)
+                return next()
+              }
+              next(error)
+            }
+
+            if (action.connect) {
+              client = RealTimeClient.connect(action.connect, cb)
+            } else if (action.rpc) {
+              if (client?.socket?.connected) {
+                client.emit(action.rpc, ...action.args, cb)
+              } else {
+                cb(new Error('not connected!'))
+              }
             } else {
-              cb(new Error('unexpected action'))
+              next(new Error('unexpected action'))
             }
           },
           done
@@ -274,10 +236,8 @@ describe('MatrixTests', function () {
       beforeEach(function userSetup(done) {
         userItem.setup((err, _options) => {
           if (err) return done(err)
-
           options = _options
-          client = options.client
-          client.on('connectionAccepted', done)
+          done()
         })
       })
 
@@ -292,18 +252,19 @@ describe('MatrixTests', function () {
 
           joinProjectWithBadAccessToken: {
             getActions(cb) {
-              cb(null, [
-                {
-                  rpc: 'joinProject',
-                  args: [
+              RealTimeClient.setAnonSession(
+                privateProjectId,
+                'invalid-access-token',
+                err => {
+                  if (err) return cb(err)
+                  cb(null, [
                     {
-                      project_id: privateProjectId,
-                      anonymousAccessToken: 'invalid-access-token',
+                      connect: privateProjectId,
+                      fails: 1,
                     },
-                  ],
-                  fails: 1,
-                },
-              ])
+                  ])
+                }
+              )
             },
           },
 
@@ -311,8 +272,7 @@ describe('MatrixTests', function () {
             getActions(cb) {
               cb(null, [
                 {
-                  rpc: 'joinProject',
-                  args: [{ project_id: privateDocId }],
+                  connect: privateDocId,
                   fails: 1,
                 },
               ])
@@ -329,8 +289,7 @@ describe('MatrixTests', function () {
             getActions(cb) {
               cb(null, [
                 {
-                  rpc: 'joinProject',
-                  args: [{ project_id: privateProjectId }],
+                  connect: privateProjectId,
                   fails: 1,
                 },
               ])
@@ -347,8 +306,7 @@ describe('MatrixTests', function () {
             getActions(cb) {
               cb(null, [
                 {
-                  rpc: 'joinProject',
-                  args: [{ project_id: privateProjectId }],
+                  connect: privateProjectId,
                   fails: 1,
                 },
                 { rpc: 'joinDoc', args: [privateDocId], fails: 1 },
@@ -379,6 +337,7 @@ describe('MatrixTests', function () {
                   RealTimeClient.getConnectedClient(
                     client.socket.sessionid,
                     (error, client) => {
+                      if (error?.message === 'not found') return done() // disconnected
                       if (error) return done(error)
                       expect(client.rooms).to.not.include(privateProjectId)
                       done()
@@ -390,6 +349,7 @@ describe('MatrixTests', function () {
                   RealTimeClient.getConnectedClient(
                     client.socket.sessionid,
                     (error, client) => {
+                      if (error?.message === 'not found') return done() // disconnected
                       if (error) return done(error)
                       expect(client.rooms).to.not.include(privateDocId)
                       done()
@@ -467,6 +427,10 @@ describe('MatrixTests', function () {
                 })
 
                 beforeEach(function sendAsUser(done) {
+                  if (!client?.socket?.connected) {
+                    // disconnected clients cannot emit messages
+                    return this.skip()
+                  }
                   const userUpdate = Object.assign({}, update, {
                     hash: 'user',
                   })

+ 8 - 32
services/real-time/test/acceptance/js/PubSubRace.js

@@ -44,14 +44,8 @@ describe('PubSubRace', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connect', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel
@@ -120,14 +114,8 @@ describe('PubSubRace', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connect', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel
@@ -203,14 +191,8 @@ describe('PubSubRace', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connect', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel
@@ -285,14 +267,8 @@ describe('PubSubRace', function () {
           },
 
           cb => {
-            this.clientA = RealTimeClient.connect()
-            return this.clientA.on('connect', cb)
-          },
-
-          cb => {
-            return this.clientA.emit(
-              'joinProject',
-              { project_id: this.project_id },
+            this.clientA = RealTimeClient.connect(
+              this.project_id,
               (error, project, privilegeLevel, protocolVersion) => {
                 this.project = project
                 this.privilegeLevel = privilegeLevel

+ 4 - 48
services/real-time/test/acceptance/js/ReceiveEditorEventTests.js

@@ -80,18 +80,7 @@ describe('receiveEditorEvent', function () {
          * Connect owner to project/doc
          */
         cb => {
-          this.owner_client = RealTimeClient.connect()
-          return this.owner_client.on('connectionAccepted', cb)
-        },
-
-        cb => {
-          return this.owner_client.emit(
-            'joinProject',
-            {
-              project_id: this.project_id,
-            },
-            cb
-          )
+          this.owner_client = RealTimeClient.connect(this.project_id, cb)
         },
 
         cb => {
@@ -120,18 +109,7 @@ describe('receiveEditorEvent', function () {
          * Connect user_a to project/doc
          */
         cb => {
-          this.user_a_client = RealTimeClient.connect()
-          return this.user_a_client.on('connectionAccepted', cb)
-        },
-
-        cb => {
-          return this.user_a_client.emit(
-            'joinProject',
-            {
-              project_id: this.project_id,
-            },
-            cb
-          )
+          this.user_a_client = RealTimeClient.connect(this.project_id, cb)
         },
         cb => {
           return this.user_a_client.emit('joinDoc', this.doc_id, cb)
@@ -159,18 +137,7 @@ describe('receiveEditorEvent', function () {
          * Connect user_b to project/doc
          */
         cb => {
-          this.user_b_client = RealTimeClient.connect()
-          return this.user_b_client.on('connectionAccepted', cb)
-        },
-
-        cb => {
-          return this.user_b_client.emit(
-            'joinProject',
-            {
-              project_id: this.project_id,
-            },
-            cb
-          )
+          this.user_b_client = RealTimeClient.connect(this.project_id, cb)
         },
         cb => {
           return this.user_b_client.emit('joinDoc', this.doc_id, cb)
@@ -202,18 +169,7 @@ describe('receiveEditorEvent', function () {
          * Connect user_c to project/doc
          */
         cb => {
-          this.user_c_client = RealTimeClient.connect()
-          return this.user_c_client.on('connectionAccepted', cb)
-        },
-
-        cb => {
-          return this.user_c_client.emit(
-            'joinProject',
-            {
-              project_id: this.project_id,
-            },
-            cb
-          )
+          this.user_c_client = RealTimeClient.connect(this.project_id, cb)
         },
         cb => {
           return this.user_c_client.emit('joinDoc', this.doc_id, cb)

+ 3 - 35
services/real-time/test/acceptance/js/ReceiveUpdateTests.js

@@ -56,39 +56,17 @@ describe('receiveUpdate', function () {
         },
 
         cb => {
-          this.clientA = RealTimeClient.connect()
-          return this.clientA.on('connectionAccepted', cb)
+          this.clientA = RealTimeClient.connect(this.project_id, cb)
         },
 
         cb => {
-          this.clientB = RealTimeClient.connect()
-          return this.clientB.on('connectionAccepted', cb)
-        },
-
-        cb => {
-          return this.clientA.emit(
-            'joinProject',
-            {
-              project_id: this.project_id,
-            },
-            cb
-          )
+          this.clientB = RealTimeClient.connect(this.project_id, cb)
         },
 
         cb => {
           return this.clientA.emit('joinDoc', this.doc_id, cb)
         },
 
-        cb => {
-          return this.clientB.emit(
-            'joinProject',
-            {
-              project_id: this.project_id,
-            },
-            cb
-          )
-        },
-
         cb => {
           return this.clientB.emit('joinDoc', this.doc_id, cb)
         },
@@ -120,19 +98,9 @@ describe('receiveUpdate', function () {
         },
 
         cb => {
-          this.clientC = RealTimeClient.connect()
-          return this.clientC.on('connectionAccepted', cb)
+          this.clientC = RealTimeClient.connect(this.project_id_second, cb)
         },
 
-        cb => {
-          return this.clientC.emit(
-            'joinProject',
-            {
-              project_id: this.project_id_second,
-            },
-            cb
-          )
-        },
         cb => {
           return this.clientC.emit('joinDoc', this.doc_id_second, cb)
         },

+ 3 - 16
services/real-time/test/acceptance/js/RouterTests.js

@@ -40,17 +40,10 @@ describe('Router', function () {
             },
 
             cb => {
-              this.client = RealTimeClient.connect()
-              return this.client.on('connectionAccepted', cb)
+              this.client = RealTimeClient.connect(this.project_id, cb)
             },
 
             cb => {
-              this.client = RealTimeClient.connect()
-              return this.client.on('connectionAccepted', cb)
-            },
-
-            cb => {
-              this.client.emit('joinProject', { project_id: this.project_id })
               return setTimeout(cb, 100)
             },
           ],
@@ -90,17 +83,11 @@ describe('Router', function () {
             },
 
             cb => {
-              this.client = RealTimeClient.connect()
-              return this.client.on('connectionAccepted', cb)
-            },
-
-            cb => {
-              this.client = RealTimeClient.connect()
-              return this.client.on('connectionAccepted', cb)
+              this.client = RealTimeClient.connect(this.project_id, cb)
             },
 
             cb => {
-              return this.client.emit('joinProject', 1, 2, 3, 4, 5, error => {
+              return this.client.emit('joinDoc', 1, 2, 3, 4, 5, error => {
                 this.error = error
                 return cb()
               })

+ 19 - 16
services/real-time/test/acceptance/js/SessionSocketsTests.js

@@ -9,21 +9,29 @@
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
 const RealTimeClient = require('./helpers/RealTimeClient')
+const FixturesManager = require('./helpers/FixturesManager')
 const Settings = require('@overleaf/settings')
 const { expect } = require('chai')
 
 describe('SessionSockets', function () {
-  before(function () {
-    return (this.checkSocket = function (fn) {
-      const client = RealTimeClient.connect()
-      client.on('connectionAccepted', fn)
-      client.on('connectionRejected', fn)
-      return null
-    })
+  beforeEach(function (done) {
+    FixturesManager.setUpProject(
+      {
+        privilegeLevel: 'owner',
+      },
+      (err, options) => {
+        if (err) return done(err)
+
+        this.checkSocket = function (fn) {
+          RealTimeClient.connect(options.project_id, fn)
+        }
+        done()
+      }
+    )
   })
 
   describe('without cookies', function () {
-    before(function () {
+    beforeEach(function () {
       return (RealTimeClient.cookie = null)
     })
 
@@ -37,7 +45,7 @@ describe('SessionSockets', function () {
   })
 
   describe('with a different cookie', function () {
-    before(function () {
+    beforeEach(function () {
       return (RealTimeClient.cookie = 'some.key=someValue')
     })
 
@@ -51,7 +59,7 @@ describe('SessionSockets', function () {
   })
 
   describe('with an invalid cookie', function () {
-    before(function (done) {
+    beforeEach(function (done) {
       RealTimeClient.setSession({}, error => {
         if (error) {
           return done(error)
@@ -74,7 +82,7 @@ describe('SessionSockets', function () {
   })
 
   describe('with a valid cookie and no matching session', function () {
-    before(function () {
+    beforeEach(function () {
       return (RealTimeClient.cookie = `${Settings.cookieName}=unknownId`)
     })
 
@@ -88,11 +96,6 @@ describe('SessionSockets', function () {
   })
 
   return describe('with a valid cookie and a matching session', function () {
-    before(function (done) {
-      RealTimeClient.setSession({}, done)
-      return null
-    })
-
     return it('should not return an error', function (done) {
       return this.checkSocket(error => {
         expect(error).to.not.exist

+ 6 - 11
services/real-time/test/acceptance/js/SessionTests.js

@@ -12,22 +12,17 @@
  */
 const { expect } = require('chai')
 
+const FixturesManager = require('./helpers/FixturesManager')
 const RealTimeClient = require('./helpers/RealTimeClient')
 
 describe('Session', function () {
   return describe('with an established session', function () {
     before(function (done) {
-      this.user_id = 'mock-user-id'
-      RealTimeClient.setSession(
-        {
-          user: { _id: this.user_id },
-        },
-        error => {
-          if (error != null) {
-            throw error
-          }
-          this.client = RealTimeClient.connect()
-          return done()
+      FixturesManager.setUpProject(
+        { privilegeLevel: 'owner' },
+        (error, options) => {
+          if (error) return done(error)
+          this.client = RealTimeClient.connect(options.project_id, done)
         }
       )
       return null

+ 5 - 2
services/real-time/test/acceptance/js/helpers/MockWebServer.js

@@ -35,8 +35,8 @@ module.exports = MockWebServer = {
     }
     const project = MockWebServer.projects[projectId]
     const privilegeLevel =
-      MockWebServer.privileges[projectId][userId] ||
-      MockWebServer.privileges[projectId][anonymousAccessToken]
+      MockWebServer.privileges[projectId]?.[userId] ||
+      MockWebServer.privileges[projectId]?.[anonymousAccessToken]
     const userMetadata = MockWebServer.userMetadata[projectId]?.[userId]
     return callback(null, project, privilegeLevel, userMetadata)
   },
@@ -65,6 +65,9 @@ module.exports = MockWebServer = {
           if (error != null) {
             return next(error)
           }
+          if (!project) {
+            return res.sendStatus(404)
+          }
           return res.json({
             project,
             privilegeLevel,

+ 31 - 10
services/real-time/test/acceptance/js/helpers/RealTimeClient.js

@@ -54,6 +54,17 @@ module.exports = Client = {
     })
   },
 
+  setAnonSession(projectId, anonymousAccessToken, callback) {
+    Client.setSession(
+      {
+        anonTokenAccess: {
+          [projectId]: anonymousAccessToken,
+        },
+      },
+      callback
+    )
+  },
+
   unsetSession(callback) {
     if (callback == null) {
       callback = function () {}
@@ -62,19 +73,29 @@ module.exports = Client = {
     return callback()
   },
 
-  connect(query) {
+  connect(projectId, callback) {
     const client = io.connect('http://localhost:3026', {
       'force new connection': true,
-      query,
+      query: new URLSearchParams({ projectId }).toString(),
+    })
+    let disconnected = false
+    client.on('disconnect', () => {
+      disconnected = true
+    })
+    client.on('connectionRejected', err => {
+      // Wait for disconnect ahead of continuing with the test sequence.
+      setTimeout(() => {
+        if (!disconnected) {
+          throw new Error('should disconnect after connectionRejected')
+        }
+        callback(err)
+      }, 10)
+    })
+    client.on('joinProjectResponse', resp => {
+      const { publicId, project, permissionsLevel, protocolVersion } = resp
+      client.publicId = publicId
+      callback(null, project, permissionsLevel, protocolVersion)
     })
-    client.on(
-      'connectionAccepted',
-      (_, publicId) => (client.publicId = publicId)
-    )
-    client.on(
-      'joinProjectResponse',
-      ({ publicId }) => (client.publicId = publicId)
-    )
     return client
   },