From e0b76f7916802394ad84c17bd5028788b6ed26e6 Mon Sep 17 00:00:00 2001 From: Mihaly Gyongyosi Date: Mon, 5 Jan 2026 14:55:52 +0100 Subject: [PATCH] Add tests --- .../apis/iam.grafana.app/v0alpha1/handlers.ts | 74 ++++++++++++++++++- .../app/features/teams/TeamGroupSync.test.tsx | 51 ++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/packages/grafana-test-utils/src/handlers/apis/iam.grafana.app/v0alpha1/handlers.ts b/packages/grafana-test-utils/src/handlers/apis/iam.grafana.app/v0alpha1/handlers.ts index 7a15817564b..e926cd025bc 100644 --- a/packages/grafana-test-utils/src/handlers/apis/iam.grafana.app/v0alpha1/handlers.ts +++ b/packages/grafana-test-utils/src/handlers/apis/iam.grafana.app/v0alpha1/handlers.ts @@ -1,5 +1,9 @@ import { HttpResponse, http } from 'msw'; +import { ExternalGroupMapping } from '@grafana/api-clients/rtkq/iam/v0alpha1'; + +import { mockTeamsMap } from '../../../../fixtures/teams'; + const getDisplayMapping = () => http.get<{ namespace: string }>('/apis/iam.grafana.app/v0alpha1/namespaces/:namespace/display', ({ request }) => { const url = new URL(request.url); @@ -26,4 +30,72 @@ const getDisplayMapping = () => }); }); -export default [getDisplayMapping()]; +const listExternalGroupMappings = () => + http.get('/apis/iam.grafana.app/v0alpha1/namespaces/:namespace/externalgroupmappings', () => { + const items = []; + for (const [teamName, data] of mockTeamsMap.entries()) { + for (const group of data.groups) { + items.push({ + apiVersion: 'iam.grafana.app/v0alpha1', + kind: 'ExternalGroupMapping', + metadata: { + name: `mapping-${teamName}-${group.groupId}`, + creationTimestamp: new Date().toISOString(), + }, + spec: { + externalGroupId: group.groupId, + teamRef: { + name: teamName, + }, + }, + }); + } + } + return HttpResponse.json({ items }); + }); + +const createExternalGroupMapping = () => + http.post<{ namespace: string }, ExternalGroupMapping>( + '/apis/iam.grafana.app/v0alpha1/namespaces/:namespace/externalgroupmappings', + async ({ request }) => { + const body = await request.json(); + const teamName = body.spec.teamRef.name; + const groupId = body.spec.externalGroupId; + + const teamData = mockTeamsMap.get(teamName); + if (teamData) { + teamData.groups.push({ groupId }); + } + + return HttpResponse.json({ + ...body, + metadata: { + name: `mapping-${teamName}-${groupId}`, + creationTimestamp: new Date().toISOString(), + ...body.metadata, + }, + }); + } + ); + +const deleteExternalGroupMapping = () => + http.delete('/apis/iam.grafana.app/v0alpha1/namespaces/:namespace/externalgroupmappings/:name', ({ params }) => { + const { name } = params; + + for (const [teamName, data] of mockTeamsMap.entries()) { + const groupIndex = data.groups.findIndex((g) => `mapping-${teamName}-${g.groupId}` === name); + if (groupIndex !== -1) { + data.groups.splice(groupIndex, 1); + return HttpResponse.json({ status: 'Success' }); + } + } + + return HttpResponse.json({ status: 'Failure', message: 'Not found' }, { status: 404 }); + }); + +export default [ + getDisplayMapping(), + listExternalGroupMappings(), + createExternalGroupMapping(), + deleteExternalGroupMapping(), +]; diff --git a/public/app/features/teams/TeamGroupSync.test.tsx b/public/app/features/teams/TeamGroupSync.test.tsx index 8f0e98eda4c..eb09e653640 100644 --- a/public/app/features/teams/TeamGroupSync.test.tsx +++ b/public/app/features/teams/TeamGroupSync.test.tsx @@ -1,6 +1,6 @@ import { render, screen, waitFor } from 'test/test-utils'; -import { setBackendSrv } from '@grafana/runtime'; +import { setBackendSrv, config } from '@grafana/runtime'; import { setupMockServer } from '@grafana/test-utils/server'; import { MOCK_TEAMS, MOCK_TEAM_GROUPS } from '@grafana/test-utils/unstable'; import { backendSrv } from 'app/core/services/backend_srv'; @@ -54,3 +54,52 @@ describe('TeamGroupSync', () => { ); }); }); + +describe('TeamGroupSync with kubernetesExternalGroupMapping enabled', () => { + const originalFeatureToggles = { ...config.featureToggles }; + const originalNamespace = config.namespace; + + beforeAll(() => { + config.featureToggles.kubernetesExternalGroupMapping = true; + config.namespace = 'default'; + }); + + afterAll(() => { + config.featureToggles = originalFeatureToggles; + config.namespace = originalNamespace; + }); + + it('should render groups table', async () => { + setup(); + expect(await screen.findAllByRole('row')).toHaveLength(MOCK_TEAM_GROUPS.length + 1); // items plus table header + }); + + it('should call add group', async () => { + const { user } = setup(); + // Wait for the groups to load so the "Add group" button appears + await screen.findAllByRole('row'); + + await user.click(screen.getAllByRole('button', { name: /add group/i })[0]); + expect(screen.getByRole('textbox', { name: /add external group/i })).toBeVisible(); + + await user.type(screen.getByRole('textbox', { name: /add external group/i }), 'new-group'); + await user.click(screen.getAllByRole('button', { name: /add group/i })[1]); + + expect(await screen.findByRole('row', { name: /new-group/i })).toBeInTheDocument(); + }); + + it('should remove group', async () => { + const { user } = setup(); + const groupToRemove = MOCK_TEAM_GROUPS[0].groupId; + + // Wait for group to be rendered + await screen.findByRole('row', { name: new RegExp(groupToRemove, 'i') }); + + // Remove group + await user.click(screen.getByRole('button', { name: `Remove group ${groupToRemove}` })); + + await waitFor(() => + expect(screen.queryByRole('row', { name: new RegExp(groupToRemove, 'i') })).not.toBeInTheDocument() + ); + }); +});