Skip to content

Commit

Permalink
feat(#1304624): Add e2e tests and add the service that lauches them i…
Browse files Browse the repository at this point in the history
…n docker compose
  • Loading branch information
matthias-goupil committed Feb 25, 2025
1 parent faee5ca commit 6df2531
Show file tree
Hide file tree
Showing 20 changed files with 647 additions and 6 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- master
- '[1-9].[0-9]+.x'
- 'feature-[a-z]+'
- 'feat-1304624-tests-e2e-playwright'
pull_request:
branches:
- master
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ jobs:
- name: Jest
run: ${{env.docker_compose_cmd}} exec -T pwa yarn test:ci

- name: e2e
run: ${{env.docker_compose_cmd}} exec -T e2e yarn test:ci

- name: Frontend Coverage Report
uses: 5monkeys/cobertura-action@v12
if: ${{ github.event_name == 'pull_request' }}
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ phpunit: ## Run php unit tests, pass the parameter "p=" to launch tests on a spe
jest: ## Run jest unit tests
@$(DOCKER_COMP) exec pwa yarn test

e2e: ## Run e2e tests
@$(DOCKER_COMP) exec e2e yarn test

jest_update: ## Run jest unit tests
@$(DOCKER_COMP) exec pwa yarn test:update

Expand Down
13 changes: 12 additions & 1 deletion compose.ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,28 @@ services:
environment:
- APP_ENV=dev
- XDEBUG_MODE=off
- TRUSTED_HOSTS=${TRUSTED_HOSTS:-^${SERVER_NAME:-|gally.localhost}|localhost|${E2E_SERVER_NAME:-gally.e2e}|php$$}

pwa:
build:
target: gally_pwa_ci
volumes:
- ./front/example-app/coverage:/usr/src/front/example-app/coverage:rw,cached,z
- ./front/pwa/coverage:/usr/src/front/pwa/coverage:rw,cached,z

environment:
- NEXT_PUBLIC_ENTRYPOINT=
- NEXT_PUBLIC_API_URL=
- REACT_APP_API_URL=
example:
build:
context: ./docker/front
target: gally_example_ci
additional_contexts:
front_src: ./front

e2e:
extends:
file: ./compose.e2e.yml
service: e2e
environment:
- CI=true
13 changes: 13 additions & 0 deletions compose.e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# E2E environment override
services:
e2e:
build:
context: .
dockerfile: ./docker/front/Dockerfile.e2e
environment:
- SERVER_BASE_URL=https://${E2E_SERVER_NAME:-gally.e2e}
- API_SERVER_BASE_URL=https://${E2E_SERVER_NAME:-gally.e2e}/${API_ROUTE_PREFIX:-api}
depends_on:
- proxy
extra_hosts:
- ${E2E_SERVER_NAME:-gally.e2e}:host-gateway
11 changes: 11 additions & 0 deletions compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ services:
- ./docker/php/conf.d/app.dev.ini:/usr/local/etc/php/conf.d/app.dev.ini:ro,z
environment:
- APP_ENV=${APP_ENV:-dev}
- TRUSTED_HOSTS=${TRUSTED_HOSTS:-^${SERVER_NAME:-|gally.localhost}|localhost|${E2E_SERVER_NAME:-gally.e2e}|php$$}
# See https://xdebug.org/docs/all_settings#mode
- XDEBUG_MODE=${XDEBUG_MODE:-off}
- PHP_IDE_CONFIG=serverName=gally
Expand All @@ -41,6 +42,9 @@ services:
environment:
# On Linux, you may want to comment the following line for improved performance
- WATCHPACK_POLLING="true"
- NEXT_PUBLIC_ENTRYPOINT=
- NEXT_PUBLIC_API_URL=
- REACT_APP_API_URL=

example:
user: ${UUID?You must set UUID env var}:${GUID?You must set GUID env var}
Expand All @@ -56,3 +60,10 @@ services:
environment:
- PUBLIC_URL=https://${SERVER_NAME:-gally.localhost}/example
- REACT_APP_API_URL=https://${SERVER_NAME:-gally.localhost}/${API_ROUTE_PREFIX:-api}

e2e:
extends:
file: ./compose.e2e.yml
service: e2e
volumes:
- ./front/e2e/:/usr/src/app:rw,cached,z
12 changes: 12 additions & 0 deletions docker/front/Dockerfile.e2e
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM mcr.microsoft.com/playwright:v1.39.0

WORKDIR /usr/src/app

COPY ./front/e2e/ .

RUN yarn install --frozen-lockfile

RUN npx playwright install chromium
RUN npx playwright install-deps chromium

CMD ["sleep", "infinity"]
5 changes: 5 additions & 0 deletions front/e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
18 changes: 18 additions & 0 deletions front/e2e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "e2e",
"private": "false",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@playwright/test": "^1.47.2",
"@types/node": "^22.6.1"
},
"scripts": {
"test": "yarn playwright test",
"test:ci": "yarn playwright test",
"test:standard": "yarn playwright test --grep @standard",
"test:premium": "yarn playwright test --grep @premium"
},
"dependencies": {}
}
22 changes: 22 additions & 0 deletions front/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineConfig, devices } from '@playwright/test'

export default defineConfig({
testDir: './tests',
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'line',
use: {
baseURL: process.env.SERVER_BASE_URL || "https://gally.local",
trace: 'on',
headless: true,
ignoreHTTPSErrors: true,
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
})
85 changes: 85 additions & 0 deletions front/e2e/tests/advanced/boost.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { test, expect } from '@playwright/test'
import { randomUUID } from 'crypto'
import { login } from '../helper/auth'
import { navigateTo } from '../helper/menu'
import { Dropdown } from '../helper/dropdown'

test('Boosts', async ({ page }) => {
await login(page)
await navigateTo(page, 'Boosts', '/fr/admin/merchandize/boost/grid')

const createButton = await page.getByTestId('createButtonResourceGrid')

/*
Grid Boost
*/
// TO DO

/*
Create Boost
*/
await createButton.click()
await expect(page).toHaveURL('/fr/admin/merchandize/boost/create')

// isActive Switch
const isActiveInput = await page.getByTestId('isActive')
const isActiveCheckbox = await isActiveInput.locator("input[type='checkbox']")

await expect(isActiveCheckbox).toBeChecked()
await isActiveInput.click()
await expect(isActiveCheckbox).not.toBeChecked()
await isActiveInput.click()
await expect(isActiveCheckbox).toBeChecked()

// Boost Preview
const previewFieldSet = await page.getByTestId('previewFieldSet')
await expect(
await previewFieldSet.getByTestId('previewRequiredMessage')
).toBeVisible()

// name InputText
const nameInput = await page.getByTestId('name')
const newName = randomUUID()

await expect(nameInput).toBeEmpty()
await nameInput.fill(newName)
await expect(nameInput).toHaveValue(newName)

// // Localized Catalogs Multiple Dropdown
const localizedCatalogs = new Dropdown(page, 'localizedCatalogs', true)
await localizedCatalogs.selectValue([
'COM French Catalog',
'COM English Catalog',
'FR French Catalog',
'EN French Catalog',
])

// Request types Multiple Dropdown
const requestTypesDropdown = new Dropdown(page, 'requestTypesDropdown', true)
await requestTypesDropdown.selectValue(['Category listing', 'Search result'])

// Model Dropdown
const modelDropdown = new Dropdown(page, 'model')
await modelDropdown.selectValue('Constante')

// Preview Boost Required Message
await expect(
await previewFieldSet.getByTestId('previewRequiredMessage')
).not.toBeVisible()

// Create the Boost and verify his existence
const saveButton = await page.getByTestId('submitButtonResourceForm')
await saveButton.click()
await expect(page).toHaveURL('/fr/admin/merchandize/boost/grid')
await expect(await page.getByText(newName)).toBeDefined() // TO DO : Manipulate the grid instead of research in the page.

/*
Edit Boost
*/
// TO DO

/*
Delete Boost
*/
// TO DO
})
45 changes: 45 additions & 0 deletions front/e2e/tests/basics/header.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test, expect } from '@playwright/test'
import { login } from '../helper/auth'

test('Header', async ({ page }) => {
await login(page)

const appBar = await page.getByTestId('appBar')
const breadcrumbs = await appBar.getByTestId('breadcrumbs')
const tooltip = await appBar.getByTestId('helpToolTip')
const tooltipOver = await tooltip.getByTestId('helpOver')
const userMenu = await appBar.getByTestId('userMenu')

// Global Tests
await expect(breadcrumbs).toBeVisible()
await expect(tooltip).toBeVisible()
await expect(tooltipOver).not.toBeVisible()
await expect(userMenu).toBeVisible()

// ToolTip tests
await tooltip.hover()
await expect(tooltipOver).toBeVisible()

// UserMenu tests
const username = await userMenu.getByTestId('username')
const email = await userMenu.getByTestId('userEmail')
const logOutButton = await userMenu.getByTestId('logOutButton')

await expect(username).toBeVisible()
await expect(await username.innerText()).toBe('[email protected]')
await expect(email).not.toBeVisible()
await expect(logOutButton).not.toBeVisible()

await userMenu.click()

await expect(email).toBeVisible()
await expect(logOutButton).toBeVisible()
await expect(await email.innerText()).toBe('[email protected]')

await logOutButton.click()

await expect(page).toHaveURL(
`${process.env.SERVER_BASE_URL || 'https://gally.local'}/fr/login`
)
await login(page)
})
72 changes: 72 additions & 0 deletions front/e2e/tests/basics/leftMenu.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { test, expect } from '@playwright/test'
import { login } from '../helper/auth'

test('Menu', async ({ page }) => {
await login(page)

const sidebar = await page.getByTestId('sidebarMenu')
const collapseButton = await page.getByTestId('sidebarMenuCollapseButton')

const labelMenuItemIconList = await await page
.getByTestId('labelMenuItemIcon')
.all()
const menuItemChildrenButtonList = await page
.getByTestId('menuItemChildrenButton')
.all()
const menuItemChildrenList = await (
await page.getByTestId('menuItemChildren')
).all()

for (const locator of menuItemChildrenList) {
await expect(locator).not.toBeVisible()
}

for (const locator of menuItemChildrenButtonList) {
await locator.click()
}

for (const locator of [...labelMenuItemIconList]) {
await expect(locator).toBeVisible()
}

const defaultSideBarWidth = (await sidebar.boundingBox())?.width

await expect(defaultSideBarWidth).not.toBe(undefined)

await collapseButton.click()

// Wait for menu transition to end
await page.evaluate(() => {
return new Promise<void>((resolve) => {
const element = document.querySelector('[data-testid="sidebarMenu"]')

element?.addEventListener('animationend', () => resolve(), {
once: true,
})
})
})

await expect((await sidebar.boundingBox())?.width).toBeLessThan(
defaultSideBarWidth as number
)

for (const locator of [...labelMenuItemIconList]) {
await expect(locator).not.toBeVisible()
}

await collapseButton.click()

await expect((await sidebar.boundingBox())?.width).toBe(defaultSideBarWidth)

for (const locator of [...labelMenuItemIconList]) {
await expect(locator).toBeVisible()
}

for (const locator of menuItemChildrenButtonList) {
await locator.click()
}

for (const locator of menuItemChildrenList) {
await expect(locator).not.toBeVisible()
}
})
Loading

0 comments on commit 6df2531

Please sign in to comment.