@@ -76,6 +76,41 @@ describe('Auth Adapter features', () => {
7676 validateAppId : ( ) => Promise . resolve ( ) ,
7777 } ;
7878
79+ // Code-based adapter that requires 'code' field (like gpgames)
80+ const codeBasedAdapter = {
81+ validateAppId : ( ) => Promise . resolve ( ) ,
82+ validateSetUp : authData => {
83+ if ( ! authData . code ) {
84+ throw new Error ( 'code is required.' ) ;
85+ }
86+ return Promise . resolve ( { save : { id : authData . id } } ) ;
87+ } ,
88+ validateUpdate : authData => {
89+ if ( ! authData . code ) {
90+ throw new Error ( 'code is required.' ) ;
91+ }
92+ return Promise . resolve ( { save : { id : authData . id } } ) ;
93+ } ,
94+ validateLogin : authData => {
95+ if ( ! authData . code ) {
96+ throw new Error ( 'code is required.' ) ;
97+ }
98+ return Promise . resolve ( { save : { id : authData . id } } ) ;
99+ } ,
100+ afterFind : authData => {
101+ // Strip sensitive 'code' field when returning to client
102+ return { id : authData . id } ;
103+ } ,
104+ } ;
105+
106+ // Simple adapter that doesn't require code
107+ const simpleAdapter = {
108+ validateAppId : ( ) => Promise . resolve ( ) ,
109+ validateSetUp : ( ) => Promise . resolve ( ) ,
110+ validateUpdate : ( ) => Promise . resolve ( ) ,
111+ validateLogin : ( ) => Promise . resolve ( ) ,
112+ } ;
113+
79114 const headers = {
80115 'Content-Type' : 'application/json' ,
81116 'X-Parse-Application-Id' : 'test' ,
@@ -1302,4 +1337,42 @@ describe('Auth Adapter features', () => {
13021337 await user . fetch ( { useMasterKey : true } ) ;
13031338 expect ( user . get ( 'authData' ) ) . toEqual ( { adapterB : { id : 'test' } } ) ;
13041339 } ) ;
1340+
1341+ it ( 'should handle multiple providers: add one while another remains unchanged (code-based)' , async ( ) => {
1342+ await reconfigureServer ( {
1343+ auth : {
1344+ codeBasedAdapter,
1345+ simpleAdapter,
1346+ } ,
1347+ } ) ;
1348+
1349+ // Login with code-based provider
1350+ const user = new Parse . User ( ) ;
1351+ await user . save ( { authData : { codeBasedAdapter : { id : 'user1' , code : 'code1' } } } ) ;
1352+ const sessionToken = user . getSessionToken ( ) ;
1353+ await user . fetch ( { sessionToken } ) ;
1354+
1355+ // At this point, authData.codeBasedAdapter only has {id: 'user1'} due to afterFind
1356+ const current = user . get ( 'authData' ) || { } ;
1357+ expect ( current . codeBasedAdapter ) . toEqual ( { id : 'user1' } ) ;
1358+
1359+ // Add a second provider while keeping the first unchanged
1360+ user . set ( 'authData' , {
1361+ ...current ,
1362+ simpleAdapter : { id : 'simple1' } ,
1363+ // codeBasedAdapter is NOT modified (no new code provided)
1364+ } ) ;
1365+
1366+ // This should succeed without requiring 'code' for codeBasedAdapter
1367+ await user . save ( null , { sessionToken } ) ;
1368+
1369+ // Verify both providers are present
1370+ const reloaded = await new Parse . Query ( Parse . User ) . get ( user . id , {
1371+ useMasterKey : true ,
1372+ } ) ;
1373+
1374+ const authData = reloaded . get ( 'authData' ) || { } ;
1375+ expect ( authData . simpleAdapter && authData . simpleAdapter . id ) . toBe ( 'simple1' ) ;
1376+ expect ( authData . codeBasedAdapter && authData . codeBasedAdapter . id ) . toBe ( 'user1' ) ;
1377+ } ) ;
13051378} ) ;
0 commit comments