@@ -333,3 +333,101 @@ test("suspended user cannot authenticate with API key", async () => {
333333 "Account suspended"
334334 ) ;
335335} ) ;
336+
337+ test ( "PATCH /api/admin/users/:id/role returns 403 for non-admin user" , async ( ) => {
338+ const { helpers } = await serve ( ) ;
339+ const { client : memberClient } = await helpers . createUser ( {
340+ site_role : "member" ,
341+ } ) ;
342+ const { user : targetUser } = await helpers . createUser ( {
343+ site_role : "member" ,
344+ } ) ;
345+
346+ await expect (
347+ memberClient . admin . users . updateRole ( targetUser . id , "admin" )
348+ ) . rejects . toThrow ( "Forbidden" ) ;
349+ } ) ;
350+
351+ test ( "PATCH /api/admin/users/:id/role returns 401 for unauthenticated request" , async ( ) => {
352+ const { helpers, url } = await serve ( ) ;
353+ const { user : targetUser } = await helpers . createUser ( {
354+ site_role : "member" ,
355+ } ) ;
356+
357+ const unauthClient = new Client ( { baseURL : url . toString ( ) } ) ;
358+
359+ await expect (
360+ unauthClient . admin . users . updateRole ( targetUser . id , "admin" )
361+ ) . rejects . toThrow ( "Unauthorized" ) ;
362+ } ) ;
363+
364+ test ( "PATCH /api/admin/users/:id/role successfully promotes user to admin" , async ( ) => {
365+ const { helpers, bindings } = await serve ( ) ;
366+ const { client : adminClient } = await helpers . createUser ( {
367+ site_role : "admin" ,
368+ } ) ;
369+ const { user : targetUser } = await helpers . createUser ( {
370+ site_role : "member" ,
371+ } ) ;
372+
373+ const result = await adminClient . admin . users . updateRole (
374+ targetUser . id ,
375+ "admin"
376+ ) ;
377+
378+ expect ( result . id ) . toBe ( targetUser . id ) ;
379+ expect ( result . site_role ) . toBe ( "admin" ) ;
380+
381+ // Verify the change persisted in the database
382+ const db = await bindings . database ( ) ;
383+ const updatedUser = await db . selectUserByID ( targetUser . id ) ;
384+ expect ( updatedUser ?. site_role ) . toBe ( "admin" ) ;
385+ } ) ;
386+
387+ test ( "PATCH /api/admin/users/:id/role successfully demotes admin to member" , async ( ) => {
388+ const { helpers, bindings } = await serve ( ) ;
389+ const { client : adminClient } = await helpers . createUser ( {
390+ site_role : "admin" ,
391+ } ) ;
392+ const { user : targetUser } = await helpers . createUser ( {
393+ site_role : "admin" ,
394+ } ) ;
395+
396+ const result = await adminClient . admin . users . updateRole (
397+ targetUser . id ,
398+ "member"
399+ ) ;
400+
401+ expect ( result . id ) . toBe ( targetUser . id ) ;
402+ expect ( result . site_role ) . toBe ( "member" ) ;
403+
404+ // Verify the change persisted in the database
405+ const db = await bindings . database ( ) ;
406+ const updatedUser = await db . selectUserByID ( targetUser . id ) ;
407+ expect ( updatedUser ?. site_role ) . toBe ( "member" ) ;
408+ } ) ;
409+
410+ test ( "PATCH /api/admin/users/:id/role returns 400 when trying to change your own role" , async ( ) => {
411+ const { helpers } = await serve ( ) ;
412+ const { client : adminClient , user : adminUser } = await helpers . createUser ( {
413+ site_role : "admin" ,
414+ } ) ;
415+
416+ await expect (
417+ adminClient . admin . users . updateRole ( adminUser . id , "member" )
418+ ) . rejects . toThrow ( "Cannot change your own role" ) ;
419+ } ) ;
420+
421+ test ( "PATCH /api/admin/users/:id/role returns 404 for non-existent user" , async ( ) => {
422+ const { helpers } = await serve ( ) ;
423+ const { client : adminClient } = await helpers . createUser ( {
424+ site_role : "admin" ,
425+ } ) ;
426+
427+ await expect (
428+ adminClient . admin . users . updateRole (
429+ "00000000-0000-0000-0000-000000000000" ,
430+ "admin"
431+ )
432+ ) . rejects . toThrow ( "User not found" ) ;
433+ } ) ;
0 commit comments