Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"lint:ts": "turbo run lint:ts --color --no-daemon",
"playwright:test": "pnpm --dir playwright run playwright:test",
"playwright:test:ui": "pnpm --dir playwright run playwright:test:ui",
"playwright:test:integration": "pnpm --dir playwright run playwright:test:integration",
"prepare": "husky",
"test": "turbo run test --concurrency 1 --color --no-daemon",
"test:cov": "turbo run test:cov --color --no-daemon",
Expand Down
18 changes: 9 additions & 9 deletions playwright/config/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ export interface Credentials {
// Users referenced in Keycloak dev realm (../keycloak/realms/realm-dev.json)
export const adminUser: Credentials = {
id: '387216f1-3b87-4211-9cac-4371125e1175',
username: 'admin',
password: 'admin',
username: process.env.CONSOLE_ADMIN_USERNAME?.trim() || 'admin',
password: process.env.CONSOLE_ADMIN_PASSWORD?.trim() || 'admin',
firstName: 'Admin',
lastName: 'ADMIN',
email: 'admin@test.com',
email: process.env.CONSOLE_ADMIN_EMAIL?.trim() || 'admin@test.com',
}
export const testUser: Credentials = {
id: 'cb8e5b4b-7b7b-40f5-935f-594f48ae6565',
username: 'test',
password: 'test',
username: process.env.CONSOLE_TEST_USERNAME?.trim() || 'test',
password: process.env.CONSOLE_TEST_PASSWORD?.trim() || 'test',
firstName: 'Jean',
lastName: 'DUPOND',
email: 'test@test.com',
email: process.env.CONSOLE_TEST_EMAIL?.trim() || 'test@test.com',
}
export const cnolletUser: Credentials = {
id: 'cb8e5b4b-7b7b-40f5-935f-594f48ae6567',
Expand Down Expand Up @@ -57,8 +57,8 @@ export async function signInCloudPiNative({
}) {
const { username, password } = credentials
await page.getByRole('link', { name: 'Se connecter' }).click()
await page.locator('#username').fill(username)
await page.locator('#password').fill(password)
await page.locator('#kc-login').click()
await page.getByRole('textbox', { name: 'Username or email' }).fill(username)
await page.getByRole('textbox', { name: 'Password' }).fill(password)
await page.getByRole('button', { name: 'Sign In' }).click()
await expect(page.locator('#top')).toContainText('Cloud π Native')
}
5 changes: 1 addition & 4 deletions playwright/e2e-tests/clusters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,7 @@ test.describe('Clusters page', () => {
confidentiality: 'dedicated',
})
// Delete
await deleteCluster({
page,
clusterName,
})
await deleteCluster(page, clusterName)
// Validate
await page.getByTestId('projectsSearchInput').fill(clusterName)
await expect(page.getByTestId('noClusterMsg')).toBeVisible()
Expand Down
55 changes: 6 additions & 49 deletions playwright/e2e-tests/projects.spec.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,17 @@
import type { Page } from '@playwright/test'
import { expect, test } from '@playwright/test'
import { faker } from '@faker-js/faker'
import {
adminUser,
clientURL,
cnolletUser,
signInCloudPiNative,
testUser,
} from '../config/console'
import { addProject, deleteValidationInput } from './utils'

// Assuming we are on a given Project page, add a random repository with given name, or a generated one
async function addRandomRepositoryToProject({
page,
repositoryName,
}: {
page: Page
repositoryName?: string
}) {
repositoryName = repositoryName ?? faker.string.alpha(10).toLowerCase()
await page.getByTestId('addRepoLink').click()
await page.getByTestId('internalRepoNameInput').fill(repositoryName)
await page
.getByTestId('externalRepoUrlInput')
.fill(`${faker.internet.url({ appendSlash: true })}myrepository.git`)
await page.getByTestId('addRepoBtn').click()
await expect(page.getByTestId(`repoTr-${repositoryName}`)).toContainText(
repositoryName,
)
return repositoryName
}

// Assuming we are on a given Project page, and we have a Repository and a Branch name,
// start branch synchronisation with this branch
async function synchronizeBranchOnRepository({
page,
repositoryName,
branchName,
}: {
page: Page
repositoryName: string
branchName?: string
}) {
branchName = branchName ?? faker.string.alpha(10).toLowerCase()
await page.getByRole('cell', { name: repositoryName }).click()
await page.getByTestId('branchNameInput').fill(branchName)
await page.getByTestId('syncRepoBtn').click()
await page
.getByTestId('resource-modal')
.getByRole('button', { name: 'Fermer' })
.click()
await expect(
page.getByText('Travail de synchronisation lancé'),
).toBeVisible()
return branchName
}
import {
addProject,
addRandomRepositoryToProject,
deleteValidationInput,
synchronizeBranchOnRepository,
} from './utils'

test.describe('Projects page', () => {
test(
Expand Down
78 changes: 70 additions & 8 deletions playwright/e2e-tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,60 @@ export async function deleteProject(page: Page, projectName: string) {
).not.toBeVisible()
}

// Assuming we are on a given Project page, add a random repository with given name, or a generated one
export async function addRandomRepositoryToProject({
page,
repositoryName,
externalRepoUrlInput,
}: {
page: Page
repositoryName?: string
externalRepoUrlInput?: string
}) {
repositoryName = repositoryName ?? faker.string.alpha(10).toLowerCase()
await page.getByTestId('addRepoLink').click()
await page.getByTestId('internalRepoNameInput').fill(repositoryName)
if (externalRepoUrlInput) {
await page
.getByTestId('externalRepoUrlInput')
.fill(externalRepoUrlInput)
} else {
await page
.getByTestId('externalRepoUrlInput')
.fill(`${faker.internet.url({ appendSlash: true })}myrepository.git`)
}
await page.getByTestId('addRepoBtn').click()
await expect(page.getByTestId(`repoTr-${repositoryName}`)).toContainText(
repositoryName,
)
return repositoryName
}

// Assuming we are on a given Project page, and we have a Repository and a Branch name,
// start branch synchronisation with this branch
export async function synchronizeBranchOnRepository({
page,
repositoryName,
branchName,
}: {
page: Page
repositoryName: string
branchName?: string
}) {
branchName = branchName ?? faker.string.alpha(10).toLowerCase()
await page.getByRole('cell', { name: repositoryName }).click()
await page.getByTestId('branchNameInput').fill(branchName)
await page.getByTestId('syncRepoBtn').click()
await page
.getByTestId('resource-modal')
.getByRole('button', { name: 'Fermer' })
.click()
await expect(
page.getByText('Travail de synchronisation lancé'),
).toBeVisible()
return branchName
}

// functions use in admin-stages.spec.ts
export async function createStage({
page,
Expand Down Expand Up @@ -172,7 +226,7 @@ export async function createCluster({
await expect(page.locator('#projects-select')).toBeVisible()
}
if (associateStageNames) {
for (const customStageName in associateStageNames) {
for (const customStageName of associateStageNames) {
await page
.getByTestId('choice-selector-search-stages-select')
.fill(customStageName)
Expand All @@ -197,13 +251,10 @@ export async function createCluster({
return clusterName
}

export async function deleteCluster({
page,
clusterName,
}: {
page: Page
clusterName: string
}) {
export async function deleteCluster(
page: Page,
clusterName: string,
) {
await page.getByTestId('menuAdministrationClusters').click()
await expect(page.getByTestId('cpin-loader')).toHaveCount(0)
await page.getByTestId('projectsSearchInput').fill(clusterName)
Expand Down Expand Up @@ -233,6 +284,17 @@ export async function createZone({ page }: { page: Page }): Promise<string> {
return zoneName
}

export async function deleteZone(
page: Page,
zoneName: string,
) {
await page.getByTestId('menuAdministrationZones').click()
await page.getByRole('link', { name: zoneName }).click()
await page.getByTestId('showDeleteZoneBtn').click()
await page.getByTestId('deleteZoneInput').fill('DELETE')
await page.getByTestId('deleteZoneBtn').click()
}

// functions use in environment.spec.ts
export async function addEnvToProject({
page,
Expand Down
124 changes: 124 additions & 0 deletions playwright/integration-tests/integration.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { expect, test } from '@playwright/test'
import { adminUser, clientURL, signInCloudPiNative } from '../config/console'

import {
addProject,
addRandomRepositoryToProject,
createCluster,
createStage,
createZone,
deleteCluster,
deleteProject,
deleteStage,
deleteZone,
} from '../e2e-tests/utils'

const zonesToDelete: string[] = []
const projectsToDelete: string[] = []
const stagesToDelete: string[] = []
const clustersToDelete: string[] = []

test.describe('Integration tests', { tag: '@integ' }, () => {
test.describe.configure({ mode: 'serial' })

test('Admin setup', async ({ page }) => {
await page.goto(clientURL)
await signInCloudPiNative({ page, credentials: adminUser })
await page.getByTestId('menuAdministrationBtn').click()
const zoneName = await createZone({ page })
zonesToDelete.push(zoneName)
// we need to attains 7 stages to be able to use associateStageNames argument in createCluster
await page.getByRole('link', { name: 'Console Cloud π Native' }).click()
const customStageName1 = await createStage({ page, check: true, stagesToDelete })
await page.getByRole('link', { name: 'Console Cloud π Native' }).click()
const customStageName2 = await createStage({ page, check: true, stagesToDelete })
await page.getByRole('link', { name: 'Console Cloud π Native' }).click()
const customStageName3 = await createStage({ page, check: true, stagesToDelete })
stagesToDelete.push(customStageName1)
stagesToDelete.push(customStageName2)
stagesToDelete.push(customStageName3)
const clusterName = await createCluster({
page,
zone: zoneName,
confidentiality: 'public',
associateStageNames: [customStageName1, customStageName2, customStageName3],
})
clustersToDelete.push(clusterName)
})

test('Cleanup admin test data', async ({ page }) => {
await page.goto(clientURL)
await signInCloudPiNative({ page, credentials: adminUser })
await page.getByTestId('menuAdministrationBtn').click()
for (const stageName of stagesToDelete) {
await deleteStage(page, stageName)
}
console.log('Stages:', stagesToDelete)
for (const clusterName of clustersToDelete) {
await deleteCluster(page, clusterName)
}
console.log('Clusters:', clustersToDelete)
for (const zoneName of zonesToDelete) {
await deleteZone(page, zoneName)
}
console.log('Zones:', zonesToDelete)
})

test('User flow', async ({ page }) => {
await page.goto(clientURL)
await signInCloudPiNative({ page, credentials: adminUser })
const project = await addProject({ page })
const projectName = project.name
projectsToDelete.push(projectName)
await addRandomRepositoryToProject({
page,
repositoryName: 'tutojava',
externalRepoUrlInput: 'https://github.com/cloud-pi-native/tuto-java.git',
})
// Check if mirror pipeline is successful
await page.getByTestId('test-tab-services').click()
const page1Promise = page.waitForEvent('popup')
await page.getByRole('link', { name: 'Gitlab' }).click()
const page1 = await page1Promise
await page1.getByTestId('group-name').filter({ hasText: 'mirror' }).click()
await expect(page1.getByTestId('status_success_borderless-icon')).toBeVisible()
// Run build pipeline and check if it is successful
await page1.getByRole('link', { name: projectName }).click()
await page1.getByTestId('group-name').filter({ hasText: 'tutojava' }).click()
await page1.getByRole('button', { name: 'Build' }).hover()
await page1.getByRole('link', { name: 'Pipelines' }).click()
await page1.getByTestId('run-pipeline-button').click()
await page1.getByTestId('run-pipeline-button').click()
await expect(
page1.getByRole('link', { name: 'Status: Passed read_secret' }),
).toBeVisible()
await expect(
page1.getByRole('link', { name: 'Status: Passed test-app' }),
).toBeVisible()
await expect(
page1.getByRole('link', { name: 'Status: Passed docker-build', exact: true }),
).toBeVisible()
await expect(
page1.getByRole('link', { name: 'Status: Passed docker-build-2' }),
).toBeVisible()
// Check if sonar scan is available
const page2Promise = page.waitForEvent('popup')
await page.getByRole('link', { name: 'SonarQube' }).click()
const page2 = await page2Promise
await page2.getByRole('button', { name: 'OpenID Connect Log in with' }).click()
await page2.getByPlaceholder('Search for projects...').fill(projectName)
await page2.getByRole('link', { name: `${projectName}-tutojava` }).click()
await expect(
page2.getByTestId('overview__quality-gate-panel').getByText('Passed', { exact: true }),
).toBeVisible()
})

test('Cleanup user test data', async ({ page }) => {
await page.goto(clientURL)
await signInCloudPiNative({ page, credentials: adminUser })
for (const projectName of projectsToDelete) {
await deleteProject(page, projectName)
}
console.log('Projects:', projectsToDelete)
})
})
1 change: 1 addition & 0 deletions playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"scripts": {
"playwright:test": "pnpm exec playwright test",
"playwright:test:ui": "pnpm exec playwright test --ui",
"playwright:test:integration": "pnpm exec playwright test -c playwright.config.integration.ts",
"format": "eslint ./ --fix"
},
"devDependencies": {
Expand Down
Loading
Loading