@@ -11,13 +11,20 @@ jest.mock('@rocket.chat/models', () => ({
1111
1212const mockFindOneAndUpdate = Users . findOneAndUpdate as jest . MockedFunction < typeof Users . findOneAndUpdate > ;
1313
14+ const fakeUser = {
15+ _id : 'user123' ,
16+ username : '@alice:example.com' ,
17+ name : '@alice:example.com' ,
18+ federated : true ,
19+ federation : { version : 1 , mui : '@alice:example.com' , origin : 'example.com' } ,
20+ } ;
21+
1422describe ( 'createOrUpdateFederatedUser' , ( ) => {
1523 beforeEach ( ( ) => {
1624 jest . clearAllMocks ( ) ;
1725 } ) ;
1826
1927 it ( 'should assign the "federated" role to the new user' , async ( ) => {
20- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
2128 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
2229
2330 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -28,7 +35,6 @@ describe('createOrUpdateFederatedUser', () => {
2835 } ) ;
2936
3037 it ( 'should not assign the "user" role to federated users' , async ( ) => {
31- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
3238 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
3339
3440 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -38,7 +44,6 @@ describe('createOrUpdateFederatedUser', () => {
3844 } ) ;
3945
4046 it ( 'should set federated=true on the created/updated user' , async ( ) => {
41- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
4247 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
4348
4449 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -48,7 +53,6 @@ describe('createOrUpdateFederatedUser', () => {
4853 } ) ;
4954
5055 it ( 'should use the provided name when supplied' , async ( ) => {
51- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
5256 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
5357
5458 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , name : 'Alice' , origin : 'example.com' } ) ;
@@ -58,7 +62,6 @@ describe('createOrUpdateFederatedUser', () => {
5862 } ) ;
5963
6064 it ( 'should default name to username when name is not provided' , async ( ) => {
61- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
6265 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
6366
6467 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -68,7 +71,6 @@ describe('createOrUpdateFederatedUser', () => {
6871 } ) ;
6972
7073 it ( 'should set initial status to OFFLINE' , async ( ) => {
71- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
7274 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
7375
7476 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -78,7 +80,6 @@ describe('createOrUpdateFederatedUser', () => {
7880 } ) ;
7981
8082 it ( 'should store the origin server in the federation object' , async ( ) => {
81- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
8283 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
8384
8485 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -88,7 +89,6 @@ describe('createOrUpdateFederatedUser', () => {
8889 } ) ;
8990
9091 it ( 'should use upsert so the user is created if not found' , async ( ) => {
91- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
9292 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
9393
9494 await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
@@ -105,8 +105,36 @@ describe('createOrUpdateFederatedUser', () => {
105105 ) ;
106106 } ) ;
107107
108+ it ( 'should throw when the returned document is not a native federated user' , async ( ) => {
109+ mockFindOneAndUpdate . mockResolvedValueOnce ( { _id : 'user123' , username : '@alice:example.com' , name : 'Alice' } as any ) ;
110+
111+ await expect ( createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ) . rejects . toThrow (
112+ 'Failed to create or update federated user: @alice:example.com' ,
113+ ) ;
114+ } ) ;
115+
116+ // callers subscribe the returned document to a room, so a projection here silently hands them a
117+ // user missing every field but the two projected ones
118+ it ( 'should not project fields away, so the full user document is returned' , async ( ) => {
119+ mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
120+
121+ await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
122+
123+ const [ , , options ] = mockFindOneAndUpdate . mock . calls [ 0 ] ;
124+ expect ( options ) . not . toHaveProperty ( 'projection' ) ;
125+ } ) ;
126+
127+ // the pre-image of an upsert that inserted is null, which would fail every first contact
128+ it ( 'should ask for the document as it looks after the upsert' , async ( ) => {
129+ mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
130+
131+ await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
132+
133+ const [ , , options ] = mockFindOneAndUpdate . mock . calls [ 0 ] ;
134+ expect ( ( options as any ) . returnDocument ) . toBe ( 'after' ) ;
135+ } ) ;
136+
108137 it ( 'should return the user returned by findOneAndUpdate' , async ( ) => {
109- const fakeUser = { _id : 'user123' , username : '@alice:example.com' } ;
110138 mockFindOneAndUpdate . mockResolvedValueOnce ( fakeUser as any ) ;
111139
112140 const result = await createOrUpdateFederatedUser ( { username : '@alice:example.com' , origin : 'example.com' } ) ;
0 commit comments