From 637b6185962adcf92f70dacfbc18660913a49e86 Mon Sep 17 00:00:00 2001 From: William Phetsinorath Date: Mon, 23 Feb 2026 12:01:42 +0100 Subject: [PATCH] chore(playwright): add full cross service e2e tests Signed-off-by: William Phetsinorath --- apps/client/src/components/AdminRoleForm.vue | 1 + apps/client/src/views/admin/ListPlugins.vue | 1 + playwright/e2e-tests/cross-services.spec.ts | 122 +++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 playwright/e2e-tests/cross-services.spec.ts diff --git a/apps/client/src/components/AdminRoleForm.vue b/apps/client/src/components/AdminRoleForm.vue index c4b953009..ef997e6fe 100644 --- a/apps/client/src/components/AdminRoleForm.vue +++ b/apps/client/src/components/AdminRoleForm.vue @@ -206,6 +206,7 @@ function closeModal() { v-for="user in users" :id="`${user.id}-cbx`" :key="user.email" + :data-testid="`user-${user.id}`" :label="`${user.lastName} ${user.firstName}`" :hint="user.email" :name="`checkbox-${user.id}`" diff --git a/apps/client/src/views/admin/ListPlugins.vue b/apps/client/src/views/admin/ListPlugins.vue index 6dc2e8540..d8a2c75ec 100644 --- a/apps/client/src/views/admin/ListPlugins.vue +++ b/apps/client/src/views/admin/ListPlugins.vue @@ -87,6 +87,7 @@ const activeAccordion = ref()

{ + let oidcGroupSuffix: string + let oidcGroupPath: string + let roleName: string + + test.beforeEach(() => { + oidcGroupSuffix = faker.string.alpha(10).toLowerCase() + oidcGroupPath = `/console/test-admin-${oidcGroupSuffix}` + roleName = `CrossTestRole-${oidcGroupSuffix}` + }) + + test('Should propagate admin role to GitLab, SonarQube, and Keycloak', { tag: '@e2e' }, async ({ page, request }) => { + // Sign in to Console + await page.goto(clientURL) + await signInCloudPiNative({ page, credentials: adminUser }) + + // Configure Plugins to use the test OIDC group + // Configure GitLab + await page.getByTestId('menuAdministrationBtn').click() + await page.getByTestId('menuAdministrationPlugins').click() + await page.getByTestId('accordion-gitlab').click() + + // Fill Admin Group Path + const gitlabAdminInput = page.getByTestId('accordion-gitlab').getByLabel('Chemin du groupe OIDC Admin') + await gitlabAdminInput.fill(oidcGroupPath) + await page.getByTestId('saveBtn').click() + await expect(page.getByText('Paramètres sauvegardés')).toBeVisible() + await page.getByTestId('accordion-gitlab').click() // Close accordion + + // Create the Role in Console + await page.getByTestId('menuAdministrationRoles').click() + await expect(page.getByTestId('role-list')).not.toContainText(roleName) + await page.getByTestId('addRoleBtn').click() + await expect(page.getByTestId('snackbar')).toContainText('Rôle ajouté') + await expect(page.getByTestId('saveBtn')).toBeDisabled() + await expect(page.getByTestId('roleNameInput')).toHaveValue('Nouveau rôle') + await page.getByTestId('roleNameInput').fill(roleName) + await page.getByTestId('oidcGroupInput').fill(oidcGroupPath) + await page.getByTestId('saveBtn').click() + await expect(page.getByTestId('role-list')).toContainText(roleName) + + // Navigate to the role's members + await page.getByTestId('test-members').click() + + // Add user + await expect(page.getByTestId('addUserBtn')).toBeDisabled() + await page + .getByTestId('addUserSuggestionInput') + .locator('input') + .fill(tcolinUser.email) + await page.getByTestId('addUserBtn').click() + await page.getByTestId('menuAdministrationUsers').click() + await expect(page.getByTestId(`user-${tcolinUser.id}`)).toContainText( + roleName, + ) + + // Check if user is in group `oidcGroupPath` + // Keycloak API + const kcToken = await getKeycloakToken(request) + const kcGroup = await getKeycloakGroup(request, kcToken, oidcGroupPath) + expect(kcGroup, 'Group should exist in Keycloak').toBeDefined() + const kcMembers = await getKeycloakGroupMembers(request, kcToken, kcGroup.id) + const kcMember = kcMembers.find((m: any) => m.email === tcolinUser.email) + expect(kcMember, 'User should be in Keycloak group').toBeDefined() + + // Check if user is in group (or is admin if we configured admin path) + // Since we configured `adminGroupPath` to `oidcGroupPath`, the user should become an Admin. + const glUser = await getGitLabUser(request, tcolinUser.email) + expect(glUser.is_admin, 'User should be GitLab Admin').toBe(true) + }) +}) + +// Helpers +async function getKeycloakToken(request: APIRequestContext) { + const config = loadKeycloakConfig() + const adminResponse = await request.post(`${config.url}/realms/master/protocol/openid-connect/token`, { + form: { + username: config.adminUser, + password: config.adminPass, + grant_type: 'password', + client_id: 'admin-cli', + }, + }) + const json = await adminResponse.json() + return json.access_token +} + +async function getKeycloakGroup(request: APIRequestContext, token: string, path: string) { + const config = loadKeycloakConfig() + const search = path.split('/').at(-1) + if (!search) { + throw new Error('Invalid group path') + } + const response = await request.get(`${config.url}/admin/realms/${config.realm}/groups`, { + headers: { Authorization: `Bearer ${token}` }, + params: { search }, + }) + const groups = await response.json() + return groups.find((g: any) => g.path === path) +} + +async function getKeycloakGroupMembers(request: APIRequestContext, token: string, groupId: string) { + const config = loadKeycloakConfig() + const response = await request.get(`${config.url}/admin/realms/${config.realm}/groups/${groupId}/members`, { + headers: { Authorization: `Bearer ${token}` }, + }) + return await response.json() +} + +async function getGitLabUser(request: APIRequestContext, email: string) { + const response = await request.get(`${process.env.GITLAB_URL}/api/v4/users`, { + headers: { 'PRIVATE-TOKEN': process.env.GITLAB_TOKEN || '' }, + params: { search: email }, + }) + const users = await response.json() + return users[0] +}