@@ -256,6 +256,14 @@ describe("assignIdpGroupsToTeam", () => {
256256 } ,
257257 ] ;
258258
259+ // Mock team ID to slug resolution
260+ mockOctokit . request . mockResolvedValueOnce ( {
261+ data : { slug : "test-team" } ,
262+ } ) ;
263+
264+ // Mock team sync availability check
265+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
266+
259267 // Mock IdP group searches (successful on first attempt)
260268 mockOctokit . request
261269 . mockResolvedValueOnce ( {
@@ -271,18 +279,18 @@ describe("assignIdpGroupsToTeam", () => {
271279 await assignIdpGroupsToTeam ( defaultInputs ) ;
272280
273281 expect ( mockOctokit . request ) . toHaveBeenCalledWith (
274- "PATCH /orgs/{org}/teams/{team_id }/team-sync/group-mappings" ,
282+ "PATCH /orgs/{org}/teams/{team_slug }/team-sync/group-mappings" ,
275283 {
276284 org : "test-org" ,
277- team_id : 123 ,
285+ team_slug : "test-team" ,
278286 groups : mockGroups ,
279287 headers : {
280288 "X-GitHub-Api-Version" : "2022-11-28" ,
281289 } ,
282290 }
283291 ) ;
284292 expect ( mockLogger . info ) . toHaveBeenCalledWith (
285- "Successfully mapped IdP groups to team 123 "
293+ "Successfully mapped IdP groups to team test-team "
286294 ) ;
287295 } ) ;
288296
@@ -293,6 +301,14 @@ describe("assignIdpGroupsToTeam", () => {
293301 group_description : "First group" ,
294302 } ;
295303
304+ // Mock team ID to slug resolution
305+ mockOctokit . request . mockResolvedValueOnce ( {
306+ data : { slug : "test-team" } ,
307+ } ) ;
308+
309+ // Mock team sync availability check
310+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
311+
296312 // First attempt throws error, second succeeds
297313 mockOctokit . request
298314 . mockRejectedValueOnce ( new Error ( "API Error" ) )
@@ -311,8 +327,15 @@ describe("assignIdpGroupsToTeam", () => {
311327 ) ;
312328 } ) ;
313329
314-
315330 it ( "should throw GithubError if IdP group not found after max retries" , async ( ) => {
331+ // Mock team ID to slug resolution
332+ mockOctokit . request . mockResolvedValueOnce ( {
333+ data : { slug : "test-team" } ,
334+ } ) ;
335+
336+ // Mock team sync availability check
337+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
338+
316339 // All 5 attempts return empty groups
317340 mockOctokit . request . mockResolvedValue ( { data : { groups : [ ] } } ) ;
318341
@@ -322,7 +345,7 @@ describe("assignIdpGroupsToTeam", () => {
322345 expect ( mockLogger . error ) . toHaveBeenCalledWith (
323346 "Failed to find IdP group with ID group-1 after 5 retries"
324347 ) ;
325- expect ( mockOctokit . request ) . toHaveBeenCalledTimes ( 5 ) ; // 5 retries for first group
348+ expect ( mockOctokit . request ) . toHaveBeenCalledTimes ( 7 ) ; // 1 for slug resolution + 1 for sync check + 5 retries for first group
326349 } ) ;
327350
328351 it ( "should handle IdP groups without description" , async ( ) => {
@@ -332,6 +355,14 @@ describe("assignIdpGroupsToTeam", () => {
332355 group_description : undefined ,
333356 } ;
334357
358+ // Mock team ID to slug resolution
359+ mockOctokit . request . mockResolvedValueOnce ( {
360+ data : { slug : "test-team" } ,
361+ } ) ;
362+
363+ // Mock team sync availability check
364+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
365+
335366 mockOctokit . request
336367 . mockResolvedValueOnce ( { data : { groups : [ mockGroup ] } } )
337368 . mockResolvedValueOnce ( { } ) ;
@@ -342,7 +373,7 @@ describe("assignIdpGroupsToTeam", () => {
342373 } ) ;
343374
344375 expect ( mockOctokit . request ) . toHaveBeenCalledWith (
345- "PATCH /orgs/{org}/teams/{team_id }/team-sync/group-mappings" ,
376+ "PATCH /orgs/{org}/teams/{team_slug }/team-sync/group-mappings" ,
346377 expect . objectContaining ( {
347378 groups : [
348379 {
@@ -365,6 +396,14 @@ describe("assignIdpGroupsToTeam", () => {
365396 } ) ;
366397
367398 it ( "should wrap non-BaseError exceptions in GithubError" , async ( ) => {
399+ // Mock team ID to slug resolution
400+ mockOctokit . request . mockResolvedValueOnce ( {
401+ data : { slug : "test-team" } ,
402+ } ) ;
403+
404+ // Mock team sync availability check
405+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
406+
368407 mockOctokit . request
369408 . mockResolvedValueOnce ( {
370409 data : { groups : [ { group_id : "group-1" , group_name : "Group One" } ] } ,
@@ -381,4 +420,118 @@ describe("assignIdpGroupsToTeam", () => {
381420 "Failed to assign IdP groups to team 123"
382421 ) ;
383422 } ) ;
423+
424+ it ( "should resolve team ID to slug" , async ( ) => {
425+ const mockGroup = {
426+ group_id : "group-1" ,
427+ group_name : "Group One" ,
428+ group_description : "First group" ,
429+ } ;
430+
431+ // Mock team ID to slug resolution
432+ mockOctokit . request . mockResolvedValueOnce ( {
433+ data : { slug : "my-team-slug" } ,
434+ } ) ;
435+
436+ // Mock team sync availability check
437+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
438+
439+ // Mock IdP group search
440+ mockOctokit . request . mockResolvedValueOnce ( {
441+ data : { groups : [ mockGroup ] } ,
442+ } ) ;
443+
444+ // Mock PATCH request
445+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
446+
447+ await assignIdpGroupsToTeam ( {
448+ ...defaultInputs ,
449+ groupsToSync : [ "group-1" ] ,
450+ } ) ;
451+
452+ expect ( mockOctokit . request ) . toHaveBeenCalledWith (
453+ "GET /orgs/{org}/teams/{team_id}" ,
454+ {
455+ org : "test-org" ,
456+ team_id : 123 ,
457+ headers : {
458+ "X-GitHub-Api-Version" : "2022-11-28" ,
459+ } ,
460+ }
461+ ) ;
462+ expect ( mockLogger . info ) . toHaveBeenCalledWith (
463+ "Resolved team ID 123 to slug: my-team-slug"
464+ ) ;
465+ } ) ;
466+
467+ it ( "should throw GithubError if team slug resolution fails" , async ( ) => {
468+ // Mock team ID to slug resolution failure
469+ mockOctokit . request . mockRejectedValueOnce ( new Error ( "Team not found" ) ) ;
470+
471+ await expect ( assignIdpGroupsToTeam ( defaultInputs ) ) . rejects . toThrow (
472+ GithubError
473+ ) ;
474+ expect ( mockLogger . error ) . toHaveBeenCalledWith (
475+ "Failed to resolve team ID 123 to slug:" ,
476+ expect . any ( Error )
477+ ) ;
478+ } ) ;
479+
480+ it ( "should exit gracefully if team sync is not available (404)" , async ( ) => {
481+ // Mock team ID to slug resolution
482+ mockOctokit . request . mockResolvedValueOnce ( {
483+ data : { slug : "test-team" } ,
484+ } ) ;
485+
486+ // Mock team sync availability check returning 404
487+ mockOctokit . request . mockRejectedValueOnce ( {
488+ status : 404 ,
489+ message : "Not Found" ,
490+ } ) ;
491+
492+ await assignIdpGroupsToTeam ( defaultInputs ) ;
493+
494+ expect ( mockLogger . warn ) . toHaveBeenCalledWith (
495+ expect . stringContaining ( "Team sync is not available for team test-team" )
496+ ) ;
497+ expect ( mockLogger . warn ) . toHaveBeenCalledWith ( "Skipping IdP group assignment" ) ;
498+ // Should not attempt to search for groups or patch
499+ expect ( mockOctokit . request ) . toHaveBeenCalledTimes ( 2 ) ; // Only slug resolution and sync check
500+ } ) ;
501+
502+ it ( "should exit gracefully if PATCH returns 404" , async ( ) => {
503+ const mockGroup = {
504+ group_id : "group-1" ,
505+ group_name : "Group One" ,
506+ group_description : "First group" ,
507+ } ;
508+
509+ // Mock team ID to slug resolution
510+ mockOctokit . request . mockResolvedValueOnce ( {
511+ data : { slug : "test-team" } ,
512+ } ) ;
513+
514+ // Mock team sync availability check
515+ mockOctokit . request . mockResolvedValueOnce ( { } ) ;
516+
517+ // Mock IdP group search
518+ mockOctokit . request . mockResolvedValueOnce ( {
519+ data : { groups : [ mockGroup ] } ,
520+ } ) ;
521+
522+ // Mock PATCH request returning 404
523+ mockOctokit . request . mockRejectedValueOnce ( {
524+ status : 404 ,
525+ message : "Not Found" ,
526+ } ) ;
527+
528+ await assignIdpGroupsToTeam ( {
529+ ...defaultInputs ,
530+ groupsToSync : [ "group-1" ] ,
531+ } ) ;
532+
533+ expect ( mockLogger . warn ) . toHaveBeenCalledWith (
534+ "Team sync endpoint not available for team 123. IdP groups were not assigned."
535+ ) ;
536+ } ) ;
384537} ) ;
0 commit comments