From 42dda753dc065fb57b85b1d2b0204daf34b12642 Mon Sep 17 00:00:00 2001 From: Matthias GOUPIL Date: Fri, 26 Jul 2024 09:54:29 +0200 Subject: [PATCH] feat(#1304624): Add e2e tests and add the service that lauches them in docker compose --- .github/workflows/ci.yml | 1 + .github/workflows/tests.yml | 3 + Makefile | 3 + compose.ci.yml | 12 +- compose.e2e.yml | 15 +++ compose.override.yml | 6 + docker/front/Dockerfile.e2e | 14 +++ front/e2e/.gitignore | 5 + front/e2e/package.json | 18 +++ front/e2e/playwright.config.ts | 51 ++++++++ front/e2e/tests/advanced/boost.spec.ts | 151 +++++++++++++++++++++++ front/e2e/tests/basics/header.spec.ts | 43 +++++++ front/e2e/tests/basics/leftMenu.spec.ts | 153 ++++++++++++++++++++++++ front/e2e/tests/basics/login.spec.ts | 53 ++++++++ front/e2e/tests/helper.ts | 17 +++ front/e2e/yarn.lock | 41 +++++++ front/yarn.lock | 43 ++++++- 17 files changed, 623 insertions(+), 6 deletions(-) create mode 100644 compose.e2e.yml create mode 100644 docker/front/Dockerfile.e2e create mode 100644 front/e2e/.gitignore create mode 100644 front/e2e/package.json create mode 100644 front/e2e/playwright.config.ts create mode 100644 front/e2e/tests/advanced/boost.spec.ts create mode 100644 front/e2e/tests/basics/header.spec.ts create mode 100644 front/e2e/tests/basics/leftMenu.spec.ts create mode 100644 front/e2e/tests/basics/login.spec.ts create mode 100644 front/e2e/tests/helper.ts create mode 100644 front/e2e/yarn.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ede57a2c4..b7046113e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - master - '[1-9].[0-9]+.x' - 'feature-[a-z]+' + - 'feat-1304624-tests-e2e-playwright' pull_request: branches: - master diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 09a662a23..00590ac29 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -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' }} diff --git a/Makefile b/Makefile index 007728a9c..bcf5dffd5 100644 --- a/Makefile +++ b/Makefile @@ -146,6 +146,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 diff --git a/compose.ci.yml b/compose.ci.yml index 11c8a6653..51632a2de 100644 --- a/compose.ci.yml +++ b/compose.ci.yml @@ -1,3 +1,5 @@ +include: + - compose.e2e.yml services: certbot: @@ -13,6 +15,7 @@ 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: @@ -20,10 +23,17 @@ services: 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: + environment: + - CI=true diff --git a/compose.e2e.yml b/compose.e2e.yml new file mode 100644 index 000000000..a158d4994 --- /dev/null +++ b/compose.e2e.yml @@ -0,0 +1,15 @@ +# 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 + volumes: + - ./front/e2e/:/usr/src/app:rw,cached,z \ No newline at end of file diff --git a/compose.override.yml b/compose.override.yml index fade4d9b5..d23c4962f 100644 --- a/compose.override.yml +++ b/compose.override.yml @@ -1,4 +1,6 @@ # Development environment override +include: + - compose.e2e.yml services: certbot: @@ -21,6 +23,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 @@ -41,6 +44,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} diff --git a/docker/front/Dockerfile.e2e b/docker/front/Dockerfile.e2e new file mode 100644 index 000000000..50c049c01 --- /dev/null +++ b/docker/front/Dockerfile.e2e @@ -0,0 +1,14 @@ +FROM mcr.microsoft.com/playwright:v1.39.0 + +WORKDIR /usr/src/app + +COPY ./front/e2e/ . + +RUN yarn install + +RUN npx playwright install chromium +RUN npx playwright install-deps chromium + +# CMD ["yarn", "test"] +# CMD ["tail", "-f", "/dev/null"] +CMD ["sleep", "infinity"] \ No newline at end of file diff --git a/front/e2e/.gitignore b/front/e2e/.gitignore new file mode 100644 index 000000000..68c5d18f0 --- /dev/null +++ b/front/e2e/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/front/e2e/package.json b/front/e2e/package.json new file mode 100644 index 000000000..271cc5cfc --- /dev/null +++ b/front/e2e/package.json @@ -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": {} +} diff --git a/front/e2e/playwright.config.ts b/front/e2e/playwright.config.ts new file mode 100644 index 000000000..d8336d739 --- /dev/null +++ b/front/e2e/playwright.config.ts @@ -0,0 +1,51 @@ +import { defineConfig, devices } from '@playwright/test' +// import dotenv from 'dotenv' +// import path from 'path' + +// Read from ".env" file. +// dotenv.config({ path: path.resolve(__dirname, '.env') }) + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: false, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + baseURL: process.env.SERVER_BASE_URL, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + headless: true, // Exécuter tous les tests en mode headless + ignoreHTTPSErrors: true, // Ignorer les erreurs HTTPS + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}) diff --git a/front/e2e/tests/advanced/boost.spec.ts b/front/e2e/tests/advanced/boost.spec.ts new file mode 100644 index 000000000..2605fb52b --- /dev/null +++ b/front/e2e/tests/advanced/boost.spec.ts @@ -0,0 +1,151 @@ +import { ICatalog, IHydraResponse } from '@elastic-suite/gally-admin-shared' +import { test, expect } from '@playwright/test' +import { randomUUID } from 'crypto' +import { login } from '../helper' + +test.describe('Boost Page', () => { + test('Check redirection to boost grid page and presence of "Create a new boost" button', async ({ + page, + }) => { + await login(page) + + await page.getByTestId('sidebarMenu').locator('a:has-text("Boost")').click() + + await expect(page).toHaveURL('/fr/admin/merchandize/boost/grid') + + const createBoostButton = await page.getByTestId('createButtonResourceGrid') + await expect(createBoostButton).toBeVisible() + }) + + test('Create Boost', async ({ page }) => { + await page.route('**/*', (route) => { + const headers = { + ...route.request().headers(), + 'Cache-Control': 'no-cache', + } + route.continue({ headers }) + }) + + await login(page) + + await page.getByTestId('sidebarMenu').locator('a:has-text("Boost")').click() + + const catalogs: IHydraResponse = await ( + await page.waitForResponse( + (response) => + response.url() === `${process.env.API_SERVER_BASE_URL}/catalogs` && + response.ok() + ) + ).json() + + await expect(page).toHaveURL('/fr/admin/merchandize/boost/grid') + await ( + await page.getByTestId('tablePagination').all() + )[0] + + const createBoostButton = await page.getByTestId('createButtonResourceGrid') + await createBoostButton.click() + + const switchIsActive = await page.getByTestId('isActive') + + await expect(await switchIsActive.locator('input')).toBeChecked() + await switchIsActive.click() + await expect(await switchIsActive.locator('input')).not.toBeChecked() + await switchIsActive.click() + await expect(await switchIsActive.locator('input')).toBeChecked() + + const modelInput = await page.getByTestId('modelInputText') + await expect(await modelInput.getAttribute('placeholder')).toBe( + 'Sélectionnez un modèle' + ) + + await expect(modelInput).toBeEmpty() + await modelInput.click() + await page.getByText('Constante').click() + await expect(await modelInput.inputValue()).toBe('Constante') + + const modelConfig = await page.getByTestId('modelConfig') + await expect(modelConfig).toBeVisible() + await expect(await modelConfig.locator('input').inputValue()).toBe('0') + + await expect( + await page.getByText('Veuillez remplir les champs requis') + ).toBeVisible() + + const boostName = randomUUID() + const nameInput = await page.getByTestId('name') + await nameInput.fill(boostName) + + await expect(await nameInput.inputValue()).toBe(boostName) + const localizedCatalogsInput = await page.getByTestId( + 'localizedCatalogsInputText' + ) + + await expect(await localizedCatalogsInput).toBeEmpty() + await localizedCatalogsInput.click() + const catalogGroupTitles = await page + .getByTestId('localizedCatalogsGroupTitle') + .allInnerTexts() + await expect(catalogGroupTitles).toEqual( + catalogs['hydra:member'].map((catalog) => catalog.name) + ) + + const catalogsCheckbox = await page + .getByTestId('localizedCatalogsCheckbox') + .all() + await catalogsCheckbox[0].click() + await catalogsCheckbox[1].click() + + expect( + await page.getByTestId('localizedCatalogsCheckbox').allInnerTexts() + ).toEqual( + catalogs['hydra:member'] + .map((catalog) => + catalog.localizedCatalogs.map( + (localizedCatalog) => localizedCatalog.name + ) + ) + .flat() + ) + let catalogsTags = await page + .getByTestId('localizedCatalogsTag') + .allInnerTexts() + + expect(catalogsTags).toEqual([ + await catalogsCheckbox[0].innerText(), + await catalogsCheckbox[1].innerText(), + ]) + await catalogsCheckbox[0].click() + catalogsTags = await page + .getByTestId('localizedCatalogsTag') + .allInnerTexts() + expect(catalogsTags).toEqual([await catalogsCheckbox[1].innerText()]) + await catalogsCheckbox[0].click() + + const requestTypesDropdownInputText = await page.getByTestId( + 'requestTypesDropdownInputText' + ) + await requestTypesDropdownInputText.click() + + const requestTypeCheckboxList = await page.getByTestId( + 'requestTypesDropdownCheckbox' + ) + + for (const tag of await requestTypeCheckboxList.all()) await tag.click() + + await expect( + await page.getByTestId('requestTypesDropdownTag').allInnerTexts() + ).toEqual(await requestTypeCheckboxList.allInnerTexts()) + + const submitButton = await page.getByTestId('submitButtonResourceForm') + await submitButton.click() + + await expect(page).toHaveURL( + `${process.env.SERVER_BASE_URL}/fr/admin/merchandize/boost/grid` + ) + + const newBoostName = await page.getByText(boostName) + + await expect(newBoostName).toBeVisible() + }) +}) diff --git a/front/e2e/tests/basics/header.spec.ts b/front/e2e/tests/basics/header.spec.ts new file mode 100644 index 000000000..dcb5368b7 --- /dev/null +++ b/front/e2e/tests/basics/header.spec.ts @@ -0,0 +1,43 @@ +import { test, expect } from '@playwright/test' +import { login } from '../helper' + +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('Admin@example.com') + 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('Admin@example.com') + + await logOutButton.click() + + await expect(page).toHaveURL(`${process.env.SERVER_BASE_URL}/fr/login`) + await login(page) +}) diff --git a/front/e2e/tests/basics/leftMenu.spec.ts b/front/e2e/tests/basics/leftMenu.spec.ts new file mode 100644 index 000000000..276a96d42 --- /dev/null +++ b/front/e2e/tests/basics/leftMenu.spec.ts @@ -0,0 +1,153 @@ +// import { test, expect } from '@playwright/test' +// import { login } from '../helper' + +// interface IItemMenu { +// label: string +// path?: string +// children?: IItemMenu[] +// } + +// const expectedMenu: IItemMenu[] = [ +// { +// label: 'ANALYSE', +// children: [ +// { +// label: 'Structure du catalogue', +// path: '/fr/admin/analyze/catalog_structure', +// }, +// ], +// }, +// { +// label: 'MERCHANDISING', +// children: [ +// { +// label: 'Catégories', +// path: '/fr/admin/merchandize/categories', +// }, +// { +// label: 'Boosts', +// path: '/fr/admin/merchandize/boost/grid', +// }, +// ], +// }, +// { +// label: 'RECHERCHE', +// children: [ +// { +// label: 'Configuration', +// children: [ +// { +// label: 'Attributs', +// path: '/fr/admin/search/configuration/attributes', +// }, +// ], +// }, +// { +// label: 'Facettes', +// path: '/fr/admin/search/facets', +// }, +// { +// label: 'Thésaurus', +// path: '/fr/admin/search/thesaurus/grid', +// }, +// { +// label: 'Recherche vectorielle', +// path: '/fr/admin/search/vector', +// }, +// ], +// }, +// { +// label: 'Paramètres', +// path: '/fr/admin/settings', +// }, +// ] + +// const extractPaths = (items) => { +// return items.reduce((acc, item) => { +// if (item.children) { +// // Si l'item a des enfants, les extraire également +// return [...acc, ...extractPaths(item.children)] +// } else if (item.path) { +// // Si l'item a un path, on le garde +// return [...acc, item] +// } +// return acc +// }, []) +// } + +// test('Left Menu', { +// tag: "@premium" +// },async ({ page }) => { +// // Correct login attempt +// await login(page) + +// // Vérifie que la sidebar est présente +// const sidebar = await page.getByTestId('sidebarMenu') +// await expect(sidebar).toBeVisible() + +// // Vérifie que le logo est bien présent dans la sidebar +// const logo = await sidebar.locator('img[alt="Logo"][width="104"]') +// await expect(logo).toBeVisible() + +// // Vérifie que le bouton de collapse est présent +// const sidebarButton = await page.getByTestId('sidebarMenuCollapseButton') +// await expect(sidebarButton).toBeVisible() + +// // Clique sur le bouton de collapse +// await sidebarButton.click() + +// // Vérifie que la sidebar est bien réduite +// await expect(sidebar).toHaveCSS('width', '66px') +// await expect(sidebar).toHaveCSS('min-width', '66px') + +// // Re-clique sur le bouton pour agrandir la sidebar +// await sidebarButton.click() + +// // Vérifie que la sidebar est de nouveau étendue +// await expect(sidebar).toHaveCSS('width', '278px') +// await expect(sidebar).toHaveCSS('min-width', '278px') + +// // const menuGroupList = await page.getByTestId('menuGroup').all() + +// // for (const [index, expectedMenuItem] of expectedMenu.entries()) { +// // const menuGroup = menuGroupList[index] +// // const menuItemIcon = await menuGroup.getByTestId('menuItemIcon') + +// // await expect(await menuItemIcon.innerText()).toEqual(expectedMenuItem.label) +// // if (expectedMenuItem.path) { +// // await expect(await menuItemIcon.locator("a")).toHaveAttribute("href", expectedMenuItem.path) + +// // // await menuItemIcon.click() +// // // await expect(page).toHaveURL(expectedMenuItem.path) +// // } else if (expectedMenuItem.children) { +// // const subGroupMenuList = await menuGroup.getByTestId('subGroupMenu').all() +// // const expectedLinks = await extractPaths(expectedMenuItem.children) + +// // for (const subGroup of subGroupMenuList) { +// // await subGroup.click() +// // } +// // const menuLinkList = await menuGroup.getByTestId('menuLinkItem').all() +// // // console.log(menuLinkList.length) +// // // for(const t of menuLinkList) { +// // // console.log("Text => ", await t.innerText()) +// // // } +// // // console.log(expectedLinks) +// // for (const [indexExpectedLink, expectedLink] of expectedLinks.entries()) { +// // const link = menuLinkList[indexExpectedLink] +// // await expect(await link.innerText()).toBe(expectedLink.label) +// // await expect(await link.locator("a")).toHaveAttribute("href", expectedLink.path) +// // // await expect(page).toHaveURL(expectedLink.path) +// // // } +// // } +// // } +// // } +// }) + + +// test('Menu', async ({page}) => { +// await login(page) +// const sidebar = await page.getByTestId('sidebarMenu') + +// await expect(sidebar).toBeVisible() + +// }) \ No newline at end of file diff --git a/front/e2e/tests/basics/login.spec.ts b/front/e2e/tests/basics/login.spec.ts new file mode 100644 index 000000000..31db91799 --- /dev/null +++ b/front/e2e/tests/basics/login.spec.ts @@ -0,0 +1,53 @@ +import { test, expect } from '@playwright/test' +import { login } from '../helper' + +const authentificationURL = `${process.env.API_SERVER_BASE_URL}/authentication_token` + +test('Login page', async ({ page }) => { + await page.goto('/fr/login') + + // Get inputs and submit button + const emailInput = await page.getByTestId('emailInput') + const passwordInput = await page.getByTestId('passwordInput') + const submitButton = await page.getByTestId('submitButton') + + // Check validation messages for empty fields + + await submitButton.click() + let emailErrorElement = await page.getByTestId('emailInputErrorMessage') + const passwordErrorElement = await page.getByTestId( + 'passwordInputErrorMessage' + ) + await expect(emailErrorElement).toHaveText('La valeur est requise') + await expect(passwordErrorElement).toHaveText('La valeur est requise') + await expect(page).toHaveURL('/fr/login') + + // Check validation messages for empty fields + + await emailInput.fill('admin@') + await submitButton.click() + emailErrorElement = await page.getByTestId('emailInputErrorMessage') + await expect(emailErrorElement).toHaveText('formError.emailInput') + + // Check validation message when log in with incorrect credentials + + await emailInput.fill('admin@example.com') + await passwordInput.fill('WrongPassword') + await submitButton.click() + + // TODO: Remplacer analyse de la requette par la détection d'un toast d'erreur + const unsuccessResponse = await ( + await page.waitForResponse( + (response) => + response.url() === authentificationURL && response.status() === 401 + ) + ).json() + + await expect(unsuccessResponse).toEqual({ + code: 401, + message: 'Identifiants invalides.', + }) + + // Check that there is a redirection when there is correct login credentials + await login(page) +}) diff --git a/front/e2e/tests/helper.ts b/front/e2e/tests/helper.ts new file mode 100644 index 000000000..87e71b6fd --- /dev/null +++ b/front/e2e/tests/helper.ts @@ -0,0 +1,17 @@ +import { Page, expect } from '@playwright/test' + +export async function login(page: Page) { + await page.goto('/fr/login') + + // Get inputs and submit button + const emailInput = await page.getByTestId('emailInput') + const passwordInput = await page.getByTestId('passwordInput') + const submitButton = await page.getByTestId('submitButton') + + // Fill with correct credentials and submit the form + await emailInput.fill('admin@example.com') + await passwordInput.fill('apassword') + await submitButton.click() + + await expect(page).toHaveURL('/fr/admin/settings/scope/catalogs') +} diff --git a/front/e2e/yarn.lock b/front/e2e/yarn.lock new file mode 100644 index 000000000..89d22a828 --- /dev/null +++ b/front/e2e/yarn.lock @@ -0,0 +1,41 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@playwright/test@^1.47.2": + version "1.47.2" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.47.2.tgz#dbe7051336bfc5cc599954214f9111181dbc7475" + integrity sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ== + dependencies: + playwright "1.47.2" + +"@types/node@^22.6.1": + version "22.7.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.4.tgz#e35d6f48dca3255ce44256ddc05dee1c23353fcc" + integrity sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg== + dependencies: + undici-types "~6.19.2" + +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +playwright-core@1.47.2: + version "1.47.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.47.2.tgz#7858da9377fa32a08be46ba47d7523dbd9460a4e" + integrity sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ== + +playwright@1.47.2: + version "1.47.2" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.47.2.tgz#155688aa06491ee21fb3e7555b748b525f86eb20" + integrity sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA== + dependencies: + playwright-core "1.47.2" + optionalDependencies: + fsevents "2.3.2" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== diff --git a/front/yarn.lock b/front/yarn.lock index affcc66fa..667f69a6c 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -2442,6 +2442,13 @@ tslib "^2.4.1" webcrypto-core "^1.7.4" +"@playwright/test@^1.47.2": + version "1.48.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.48.0.tgz#4b81434a3ca75e2a6f82a645287784223a45434c" + integrity sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w== + dependencies: + playwright "1.48.0" + "@pmmmwh/react-refresh-webpack-plugin@^0.5.3": version "0.5.10" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8" @@ -4030,6 +4037,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.11.tgz#cbb15c12ca7c16c85a72b6bdc4d4b01151bb3cae" integrity sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA== +"@types/node@^22.6.1": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -8828,6 +8842,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@2.3.2, fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + fsevents@^1.2.7: version "1.2.13" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" @@ -8836,11 +8855,6 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - fulcon@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/fulcon/-/fulcon-1.0.2.tgz#8a4dfda4c73fcd9cc62a79d5045c392b45547320" @@ -13165,6 +13179,20 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" +playwright-core@1.48.0: + version "1.48.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.48.0.tgz#34d209dd4aba8fccd4a96116f1c4f7630f868722" + integrity sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA== + +playwright@1.48.0: + version "1.48.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.48.0.tgz#00855d9a25f1991d422867f1c32af5d90f457b48" + integrity sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA== + dependencies: + playwright-core "1.48.0" + optionalDependencies: + fsevents "2.3.2" + pnp-webpack-plugin@1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" @@ -16579,6 +16607,11 @@ undefsafe@^2.0.5: resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + undici@^5.2.0: version "5.14.0" resolved "https://registry.yarnpkg.com/undici/-/undici-5.14.0.tgz#1169d0cdee06a4ffdd30810f6228d57998884d00"