diff --git a/playwright/README.md b/playwright/README.md index 683df6371..d47e6602c 100644 --- a/playwright/README.md +++ b/playwright/README.md @@ -53,9 +53,13 @@ $ export CONSOLE_ADMIN_EMAIL= $ export CONSOLE_TEST_USERNAME= $ export CONSOLE_TEST_PASSWORD= $ export CONSOLE_TEST_EMAIL= +$ export CONSOLE_SECOND_TEST_USERNAME= +$ export CONSOLE_SECOND_TEST_PASSWORD= +$ export CONSOLE_SECOND_TEST_EMAIL= $ export CONSOLE_GLOBAL_TIMEOUT='900000' $ export CONSOLE_EXPECT_TIMEOUT='900000' $ export CONSOLE_DESTINATION_CLUSTER= +$ export CONSOLE_VALUES_FILE= ``` On peut lancer ensuite les tests : diff --git a/playwright/config/console.ts b/playwright/config/console.ts index 1e7ffe8f7..fb6aa11b3 100644 --- a/playwright/config/console.ts +++ b/playwright/config/console.ts @@ -48,6 +48,16 @@ export const tcolinUser: Credentials = { email: 'thibault.colin@test.com', } +// User for integration test +export const secondTestUser: Credentials = { + id: 'test', + username: process.env.CONSOLE_SECOND_TEST_USERNAME?.trim() || 'anothertest', + password: process.env.CONSOLE_SECOND_TEST_PASSWORD?.trim() || 'anothertest', + firstName: 'test', + lastName: 'test', + email: process.env.CONSOLE_SECOND_TEST_EMAIL?.trim() || 'anothertest@test.com', +} + export async function signInCloudPiNative({ page, credentials, diff --git a/playwright/integration-tests/user-flow.spec.ts b/playwright/integration-tests/user-flow.spec.ts index 50447ec97..3c5953808 100644 --- a/playwright/integration-tests/user-flow.spec.ts +++ b/playwright/integration-tests/user-flow.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test' -import { adminUser, testUser, clientURL, signInCloudPiNative } from '../config/console' +import { adminUser, secondTestUser, testUser, clientURL, signInCloudPiNative } from '../config/console' import { addProject, @@ -8,13 +8,14 @@ import { } from '../e2e-tests/utils' const projectsToDelete: string[] = [] +const projectName = 'socleprojecttest' +const repositoryName = 'socle-project-test' +const destinationCluster = process.env.CONSOLE_DESTINATION_CLUSTER || 'cpin-app-hp' +const helmValuesFiles = process.env.CONSOLE_VALUES_FILE || 'values-cpin-hp.yaml' +projectsToDelete.push(projectName) -test.describe('Integration tests user flow', { tag: '@integ' }, () => { +test.describe('Integration tests user flow: project creation', { tag: '@integ' }, () => { test.describe.configure({ mode: 'serial' }) - const projectName = 'socleprojecttest' - const repositoryName = 'socle-project-test' - const destinationCluster = process.env.CONSOLE_DESTINATION_CLUSTER || 'cpin-app-hp' - projectsToDelete.push(projectName) test('Preliminary checks', { tag: '@replayable' }, async ({ page }) => { await page.goto(clientURL) @@ -64,10 +65,14 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { await page.getByRole('cell', { name: repositoryName }).click() await page.getByTestId('deployRevisionInput').fill('main') await page.getByTestId('deployPathInput').fill('helm/') - await page.getByTestId('helmValuesFilesTextarea').fill('values-cpin-hp.yaml') + await page.getByTestId('helmValuesFilesTextarea').fill(helmValuesFiles) await page.getByTestId('updateRepoBtn').click() await expect(page.getByRole('heading', { name: 'Opération en cours...' })).toBeVisible() }) +}) + +test.describe('Integration tests user flow: first checks', { tag: '@integ' }, () => { + test.describe.configure({ mode: 'serial' }) test('Check Vault kv', { tag: '@replayable' }, async ({ page }) => { await page.goto(clientURL) @@ -90,6 +95,37 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { await expect(page1.getByRole('link', { name: 'forge-dso' })).not.toBeVisible() }) + test('Project permissions', async ({ page }) => { + await page.goto(clientURL) + await signInCloudPiNative({ page, credentials: testUser }) + await page.getByTestId('menuMyProjects').click() + await page.getByRole('link', { name: projectName }).click() + // Add user to project + await page.getByTestId('test-tab-team').click() + await page.getByTestId('addUserSuggestionInput').locator('input').fill(secondTestUser.email) + await page.getByTestId('addUserBtn').click() + await expect(page.getByRole('heading', { name: 'Reprovisionnement nécessaire' })).toBeVisible() + // Create read-only role + await page.getByTestId('test-tab-roles').click() + await page.getByTestId('addRoleBtn').click() + await page.getByTestId('roleNameInput').fill('readOnly') + await page.getByText('Afficher les secrets Permet d').click() + await page.getByText('Voir les environnements').click() + await page.getByText('Voir les dépôts Permet de').click() + await page.getByTestId('saveBtn').click() + await expect(page.getByText('Rôle mis à jour')).toBeVisible() + await expect(page.getByRole('heading', { name: 'Reprovisionnement nécessaire' })).toBeVisible() + // Add user to read-only role + await page.getByTestId('test-members').click() + await page.getByLabel('Rôles', { exact: true }).getByText(secondTestUser.email).click() + await expect(page.getByText('Rôle mis à jour')).toBeVisible() + await expect(page.getByRole('heading', { name: 'Reprovisionnement nécessaire' })).toBeVisible() + // Replay project hooks + await page.getByTestId('replayHooksBtn').click() + await expect(page.getByRole('heading', { name: 'Opération en cours...' })).toBeVisible() + await expect(page.getByText('Le projet a été reprovisionn')).toBeVisible() + }) + test('Pipelines run', { tag: '@replayable' }, async ({ page }) => { await page.goto(clientURL) await signInCloudPiNative({ page, credentials: testUser }) @@ -119,6 +155,10 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { page1.getByRole('link', { name: 'Status: Passed test-sonar' }), ).toBeVisible() }) +}) + +test.describe('Integration tests user flow: after pipelines checks', { tag: '@integ' }, () => { + test.describe.configure({ mode: 'serial' }) test('Prepare ArgoCD deployment', async ({ page }) => { await page.goto(clientURL) @@ -177,6 +217,10 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { // Check trivy scan result, hopefully will stay at C await expect(page1.getByRole('button', { name: 'C', exact: true })).toBeVisible() }) +}) + +test.describe('Integration tests user flow: deployment and metrics', { tag: '@integ' }, () => { + test.describe.configure({ mode: 'serial' }) test('ArgoCD deployment', { tag: '@replayable' }, async ({ page }) => { await page.goto(clientURL) @@ -232,11 +276,35 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { await expect(page1.getByRole('cell', { name: 'app_kubernetes_io_name' }).nth(1)).toBeVisible() await expect(page1.getByText('demo-java-helm').nth(1)).toBeVisible() }) +}) + +test.describe('Integration tests user flow: Cleanup', { tag: '@integ' }, () => { + test.describe.configure({ mode: 'serial' }) - test('Cleanup user test data', async ({ page }) => { + test('Remove permissions and user', async ({ page }) => { + await page.goto(clientURL) + await signInCloudPiNative({ page, credentials: testUser }) + await page.getByTestId('menuMyProjects').click() + await page.getByRole('link', { name: projectName }).click() + // Remove role membership + await page.getByTestId('test-tab-roles').click() + await page.getByRole('button', { name: 'readOnly' }).click() + await page.getByTestId('test-members').click() + await page.getByLabel('Rôles', { exact: true }).getByText(secondTestUser.email).click() + await expect(page.getByText('Rôle mis à jour')).toBeVisible() + await expect(page.getByRole('heading', { name: 'Reprovisionnement nécessaire' })).toBeVisible() + // Remove role + await page.getByTestId('test-general').click() + await page.getByTestId('deleteBtn').click() + await page.getByText('Rôle supprimé').click() + // Remove project membership + await page.getByTestId('test-tab-team').click() + await page.getByTitle(`Retirer ${secondTestUser.email} du`).click() + }) + + test('Remove stage', async ({ page }) => { await page.goto(clientURL) await signInCloudPiNative({ page, credentials: testUser }) - // ArgoCD deployment will be deleted when stage is deleted await page.getByTestId('menuMyProjects').click() await page.getByRole('link', { name: projectName }).click() await page.getByRole('cell', { name: 'integ' }).click() @@ -247,6 +315,7 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { await expect( page.getByRole('cell', { name: 'Aucun environnement existant' }), ).toBeVisible() + // ArgoCD deployment will be deleted when stage is deleted await page.getByTestId('test-tab-services').click() const page1Promise = page.waitForEvent('popup') await page.getByRole('link', { name: 'ArgoCD DSO' }).click() @@ -255,7 +324,13 @@ test.describe('Integration tests user flow', { tag: '@integ' }, () => { await expect( page1.locator('span').filter({ hasText: `${projectName}-integ-socle-` }), ).not.toBeVisible() - // Remove repository from project + }) + + test('Remove repository from project', async ({ page }) => { + await page.goto(clientURL) + await signInCloudPiNative({ page, credentials: testUser }) + await page.getByTestId('menuMyProjects').click() + await page.getByRole('link', { name: projectName }).click() await page.getByTestId('test-tab-resources').click() await page.getByRole('cell', { name: repositoryName }).click() await page.getByTestId('showDeleteRepoBtn').click()