Merge remote-tracking branch 'origin/master' into 3505-feature-introduce-encrypted-jwts-in-backend-federation-communication

This commit is contained in:
clauspeterhuebner 2025-07-17 22:44:54 +02:00
commit 1b6d894bd3
30 changed files with 626 additions and 163 deletions

View File

@ -24,7 +24,7 @@ jobs:
- name: Prepare test system
run: |
sudo chown runner:docker -R *
bun install
bun install --frozen-lockfile
sudo cp ./nginx/e2e-test.conf /etc/nginx/sites-available/default
- name: Boot up test system | seed backend
@ -40,9 +40,8 @@ jobs:
cd backend
cp .env.test_e2e .env
cd ..
bun turbo backend#build
bun turbo frontend#build
bun turbo backend#start frontend#start --env-mode=loose &
bun turbo backend#build frontend#build --env-mode=loose
bun turbo backend#start frontend#start --env-mode=loose &
- name: End-to-end tests | prepare
run: |
@ -106,3 +105,154 @@ jobs:
with:
name: backend-logs-pr-#${{ steps.pr.outputs.number }}
path: /home/runner/work/gradido/gradido/logs/backend
end-to-end-tests-playwright:
name: End-to-End Tests Playwright
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set Node.js version
uses: actions/setup-node@v4
with:
node-version: '18.20.7'
- name: install bun
uses: oven-sh/setup-bun@v2
- name: Boot up test system | docker-compose mariadb mailserver
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb mailserver
- name: Prepare test system
run: |
sudo chown runner:docker -R *
bun install --frozen-lockfile
sudo cp ./nginx/e2e-test.conf /etc/nginx/sites-available/default
- name: Boot up test system | seed backend
run: bun turbo seed
- name: copy test config
run: |
cd frontend
cp .env.test_e2e .env
cd ../backend
cp .env.test_e2e .env
- name: Moving logs after seeding
run: |
mkdir -p /home/runner/work/gradido/gradido/logs/backend/seed
mv /home/runner/work/gradido/gradido/logs/backend/*.log /home/runner/work/gradido/gradido/logs/backend/seed/
- name: Boot up test system | docker-compose backend, frontend
run: |
bun turbo backend#build frontend#build --env-mode=loose
bun turbo backend#start frontend#start --env-mode=loose &
- name: End-to-end tests | prepare
run: |
cd e2e-tests/playwright/typescript
bun install
- name: wait for frontend and backend to be ready
run: |
until nc -z 127.0.0.1 3000; do echo waiting for frontend; sleep 1; done;
until nc -z 127.0.0.1 4000; do echo waiting for backend; sleep 1; done;
- name: Start local nginx webserver
run: |
sudo nginx -t
sudo systemctl start nginx
- name: wait for nginx and mailserver to be ready
run: |
until nc -z 127.0.0.1 80; do echo waiting for nginx; sleep 1; done;
until nc -z 127.0.0.1 1025; do echo waiting for mailserver; sleep 1; done;
- name: End-to-end tests | run tests
id: e2e-tests
run: |
cd e2e-tests/playwright/typescript
bun run test --project="Google Chrome"
- name: End-to-end tests | if tests failed, upload video
id: e2e-video
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: cypress-videos-pr-#${{ steps.pr.outputs.number }}
path: /home/runner/work/gradido/gradido/e2e-tests/playwright/typescript/test-results
end-to-end-tests-playwright-java:
name: End-to-End Tests Playwright java
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set Node.js version
uses: actions/setup-node@v4
with:
node-version: '18.20.7'
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: install bun
uses: oven-sh/setup-bun@v2
- name: Boot up test system | docker-compose mariadb mailserver
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach mariadb mailserver
- name: Prepare test system
run: |
sudo chown runner:docker -R *
bun install
sudo cp ./nginx/e2e-test.conf /etc/nginx/sites-available/default
- name: Boot up test system | seed backend
run: bun turbo seed
- name: Moving logs after seeding
run: |
mkdir -p /home/runner/work/gradido/gradido/logs/backend/seed
mv /home/runner/work/gradido/gradido/logs/backend/*.log /home/runner/work/gradido/gradido/logs/backend/seed/
- name: Boot up test system | docker-compose backend, frontend
run: |
cd backend
cp .env.test_e2e .env
cd ..
bun turbo backend#build frontend#build --env-mode=loose
bun turbo backend#start frontend#start --env-mode=loose &
- name: End-to-end tests | prepare
run: |
cd e2e-tests/playwright/typescript
bun install
- name: wait for frontend and backend to be ready
run: |
until nc -z 127.0.0.1 3000; do echo waiting for frontend; sleep 1; done;
until nc -z 127.0.0.1 4000; do echo waiting for backend; sleep 1; done;
- name: Start local nginx webserver
run: |
sudo nginx -t
sudo systemctl start nginx
- name: wait for nginx and mailserver to be ready
run: |
until nc -z 127.0.0.1 80; do echo waiting for nginx; sleep 1; done;
until nc -z 127.0.0.1 1025; do echo waiting for mailserver; sleep 1; done;
- name: End-to-end tests | run tests
id: e2e-tests
run: |
cd e2e-tests/playwright/java
mvn -B install -D skipTests --no-transfer-progress
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps"
mvn test

View File

@ -4,6 +4,7 @@ JWT_EXPIRES_IN=2m
GDT_ACTIVE=false
HUMHUB_ACTIVE=false
GMS_ACTIVE=false
USE_CRYPTO_WORKER=true
# Email
EMAIL=true

View File

@ -58,6 +58,7 @@ const run = async () => {
const { con } = server
await cleanDB()
logger.info('##seed## clean database successful...')
logger.info(`crypto worker enabled: ${CONFIG.USE_CRYPTO_WORKER}`)
// seed home community
await writeHomeCommunityEntry()

View File

@ -3,4 +3,4 @@ cypress/screenshots/
cypress/videos/
cypress/reports/
cucumber-messages.ndjson
**/target

View File

@ -1,42 +0,0 @@
###############################################################################
# Dockerfile to create a ready-to-use Playwright Docker image for end-to-end
# testing.
#
# To avoid hardcoded versoning of Playwright, this Dockerfile is a custom
# version of the ready-to-use Dockerfile privided by Playwright developement
# (https://github.com/microsoft/playwright/blob/main/utils/docker/Dockerfile.focal)
#
# Here the latest stable versions of the browsers Chromium, Firefox, and Webkit
# (Safari) are installed, icluding all dependencies based on Ubuntu specified by
# Playwright developement.
###############################################################################
FROM ubuntu:focal
# set a timezone for the Playwright browser dependency installation
ARG TZ=Europe/Berlin
ARG DOCKER_WORKDIR=/tests/
WORKDIR $DOCKER_WORKDIR
# package manager preparation
RUN apt-get -qq update && apt-get install -qq -y curl gpg > /dev/null
# for Node.js
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash -
# for Yarn
RUN curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
# install node v16 and Yarn
RUN apt-get -qq update && apt-get install -qq -y nodejs yarn
COPY tests/package.json tests/yarn.lock $DOCKER_WORKDIR
# install Playwright with all dependencies
# for the browsers chromium, firefox, and webkit
RUN yarn install && yarn playwright install --with-deps
# clean up
RUN rm -rf /var/lib/apt/lists/* && apt-get -qq clean
COPY tests/ $DOCKER_WORKDIR

View File

@ -1,24 +0,0 @@
# Gradido End-to-End Testing with [Playwright](https://playwright.dev/) (CI-ready via Docker)
A sample setup to show-case Playwright (using Typescript) as an end-to-end testing tool for Gradido runniing in a Docker container.
Here we have a simple UI-based happy path login test running against the DEV system.
## Precondition
Since dependencies and configurations for Github Actions integration is not set up yet, please run in root directory
```bash
docker-compose up
```
to boot up the DEV system, before running the test.
## Execute the test
```bash
# build a Docker image from the Dockerfile
docker build -t gradido_e2e-tests-playwright .
# run the Docker container and execute the given tests
docker run -it --network=host gradido_e2e-tests-playwright yarn playwright-e2e-tests
```

View File

@ -0,0 +1,12 @@
# gradido-e2e-tests-playwright with java
Experimental End-to-end tests with Playwright and Java
## Prerequisites
- Java 17
- Maven
- Playwright
- Gradle
- Git

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.gradido</groupId>
<artifactId>gradido-e2e-tests-playwright</artifactId>
<version>0.0.1</version>
<name>Gradido Playwright End-to-End Tests in Java</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.52.0</version>
</dependency>
<!-- JUnit Jupiter API & Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<!-- References to interface static methods are allowed only at source level 1.8 or above -->
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
<configuration>
<includes>
<include>**/*Test*.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,69 @@
package net.gradido.e2e.base;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Tracing;
import org.junit.jupiter.api.*;
import java.nio.file.Path;
import java.nio.file.Paths;
// Subclasses will inherit PER_CLASS behavior.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTest {
protected Playwright playwright;
protected Browser browser;
@BeforeAll
void setUpAll() {
playwright = Playwright.create();
browser = playwright.chromium().launch();
}
@AfterAll
void tearDownAll() {
playwright.close();
}
// New instance for each test method.
protected BrowserContext context;
protected Page page;
protected Path currentTracePath;
@BeforeEach
void setUp(TestInfo testInfo) {
context = browser.newContext(
new Browser.NewContextOptions().setBaseURL("http://localhost:3000")
);
context.route("**/*", route -> {
String url = route.request().url();
// we skip fontawesome and googleapis requests, we don't need them for functions test, but they cost time
if (url.contains("use.fontawesome.com") || url.contains("fonts.googleapis.com")) {
route.abort();
return;
}
route.resume();
});
// Start tracing before creating
String testName = testInfo.getDisplayName().replaceAll("[^a-zA-Z0-9]", "");
currentTracePath = Paths.get("target/traces/" + testName + ".zip");
context.tracing().start(new Tracing.StartOptions()
.setScreenshots(true)
.setSnapshots(true)
.setSources(true));
page = context.newPage();
}
@AfterEach
void tearDown() {
// Stop tracing and export it into a zip archive.
context.tracing().stop(new Tracing.StopOptions().setPath(currentTracePath));
page.close();
context.close();
}
}

View File

@ -0,0 +1,26 @@
package net.gradido.e2e.components;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class Toasts {
public final Locator toastSlot;
public final Locator toastTypeError;
public final Locator toastTitle;
public final Locator toastMessage;
public Toasts(Page page) {
toastSlot = page.locator("#__BVID__toaster-container");
toastTypeError = toastSlot.locator(".toast.text-bg-danger");
toastTitle = toastTypeError.locator(".gdd-toaster-title");
toastMessage = toastTypeError.locator(".gdd-toaster-body");
}
public void assertErrorToastVisible() {
toastTypeError.waitFor();
assertTrue(toastTitle.isVisible());
assertTrue(toastMessage.isVisible());
}
}

View File

@ -0,0 +1,32 @@
package net.gradido.e2e.pages;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Response;
public class LoginPage {
private final Page page;
private final Locator emailInput;
private final Locator passwordInput;
private final Locator submitButton;
public LoginPage(Page page) {
this.page = page;
emailInput = page.locator("input[name='email']");
passwordInput = page.locator("input[name='password']");
submitButton = page.locator("button[type='submit']");
}
public void login(String email, String password) {
emailInput.fill(email);
passwordInput.fill(password);
Response response = page.waitForResponse("**/graphql", () -> {
submitButton.click();
});
}
public void navigate() {
page.navigate("http://localhost:3000/login");
}
}

View File

@ -0,0 +1,26 @@
package net.gradido.e2e.tests;
import net.gradido.e2e.base.BaseTest;
import net.gradido.e2e.pages.LoginPage;
import net.gradido.e2e.components.Toasts;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class InvalidLoginTest extends BaseTest {
private LoginPage loginPage;
@BeforeEach
void initPageObjects() {
loginPage = new LoginPage(page);
}
@Test
void invalidUserSeesError() {
loginPage.navigate();
loginPage.login("peter@lustig.de", "wrongpass");
Toasts toast = new Toasts(page);
toast.assertErrorToastVisible();
}
}

View File

@ -0,0 +1,28 @@
package net.gradido.e2e.tests;
import net.gradido.e2e.base.BaseTest;
import net.gradido.e2e.pages.LoginPage;
import net.gradido.e2e.components.Toasts;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ValidLoginTest extends BaseTest {
private LoginPage loginPage;
@BeforeEach
void initPageObjects() {
loginPage = new LoginPage(page);
}
@Test
void validUserCanLogin() {
loginPage.navigate();
loginPage.login("peter@lustig.de", "Aa12345_");
page.waitForURL("http://localhost:3000/overview");
assertTrue(page.url().contains("/overview"));
}
}

View File

@ -0,0 +1,5 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = same_thread
junit.jupiter.execution.parallel.mode.classes.default = concurrent
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=0.5

View File

@ -1,10 +0,0 @@
import { FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
process.env.EMAIL = 'bibi@bloxberg.de';
process.env.PASSWORD = 'Aa12345_';
process.env.GMS_ACTIVE = false;
process.env.HUMHUB_ACTIVE = false;
}
export default globalSetup;

View File

@ -1,15 +0,0 @@
import { test, expect } from '@playwright/test';
import { LoginPage } from './models/login_page';
import { WelcomePage } from './models/welcome_page';
test('Gradido login test (happy path)', async ({ page }) => {
const { EMAIL, PASSWORD } = process.env;
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.enterEmail(EMAIL);
await loginPage.enterPassword(PASSWORD);
await loginPage.submitLogin();
// assertions
await expect(page).toHaveURL('./overview');
});

View File

@ -1,33 +0,0 @@
import { expect, test, Locator, Page } from '@playwright/test';
export class LoginPage {
readonly page: Page;
readonly url: string;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitBtn: Locator;
constructor(page: Page) {
this.page = page;
this.url = './login';
this.emailInput = page.locator('id=Email-input-field');
this.passwordInput = page.locator('id=Password-input-field');
this.submitBtn = page.locator('text=Login');
}
async goto() {
await this.page.goto(this.url);
}
async enterEmail(email: string) {
await this.emailInput.fill(email);
}
async enterPassword(password: string) {
await this.passwordInput.fill(password);
}
async submitLogin() {
await this.submitBtn.click();
}
}

View File

@ -1,13 +0,0 @@
import { expect, Locator, Page } from '@playwright/test';
export class WelcomePage {
readonly page: Page;
readonly url: string;
readonly profileLink: Locator;
constructor(page: Page){
this.page = page;
this.url = './overview';
this.profileLink = page.locator('href=/profile');
}
}

View File

@ -1,21 +0,0 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
globalSetup: require.resolve('./global-setup'),
ignoreHTTPSErrors: true,
locale: 'de-DE',
reporter: process.env.CI ? 'github' : 'list',
retries: 1,
screenshot: 'only-on-failure',
testDir: '.',
timeout: 30000,
trace: 'on-first-retry',
video: 'never',
viewport: { width: 1280, height: 720 },
use: {
baseURL: process.env.URL || 'http://127.0.0.1:3000',
browserName: 'webkit',
},
};
export default config;

View File

@ -0,0 +1,7 @@
# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

View File

@ -0,0 +1,22 @@
import type { Locator, Page } from '@playwright/test'
import { expect } from '@playwright/test'
export class Toasts {
public readonly toastSlot: Locator
public readonly toastTypeError: Locator
public readonly toastTitle: Locator
public readonly toastMessage: Locator
constructor(page: Page) {
this.toastSlot = page.locator('#__BVID__toaster-container')
this.toastTypeError = this.toastSlot.locator('.toast.text-bg-danger')
this.toastTitle = this.toastTypeError.locator('.gdd-toaster-title')
this.toastMessage = this.toastTypeError.locator('.gdd-toaster-body')
}
async assertErrorToastVisible(): Promise<void> {
await this.toastTypeError.waitFor({ state: 'visible' })
expect(this.toastTitle).toBeVisible()
expect(this.toastMessage).toBeVisible()
}
}

View File

@ -0,0 +1 @@
export const FRONTEND_URL = "http://localhost:3000"

View File

@ -0,0 +1,13 @@
{
"name": "typescript",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@playwright/test": "^1.53.1",
"@types/node": "^24.0.7"
},
"scripts": {
"test": "playwright test --reporter=list"
}
}

View File

@ -0,0 +1,28 @@
import type { Locator, Page } from '@playwright/test'
import { FRONTEND_URL } from '../config'
export class LoginPage {
readonly page: Page
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
constructor(page: Page) {
this.page = page
this.emailInput = page.locator('#email-input-field')
this.passwordInput = page.locator('#password-input-field')
this.submitButton = page.locator("button[type='submit']")
}
async goto() {
await this.page.goto(`${FRONTEND_URL}/login`)
}
async login(email: string, password: string) {
await this.emailInput.fill(email)
await this.passwordInput.fill(password)
const responsePromise = this.page.waitForResponse('**/graphql')
await this.submitButton.click()
await responsePromise
}
}

View File

@ -0,0 +1,82 @@
import { defineConfig, devices } from '@playwright/test';
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests',
// Glob patterns or regular expressions that match test files.
testMatch: '*',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: 2,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? '90%' : '75%',
/* 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: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
video: 'on-first-retry',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
{
name: 'Google Chrome',
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
},
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://localhost:3000',
// reuseExistingServer: !process.env.CI,
// },
});

View File

@ -0,0 +1,13 @@
import { test, expect } from '@playwright/test'
import { LoginPage } from '../pages/LoginPage'
import { Toasts } from '../components/Toasts'
test('invalid login', async ({ page }) => {
const loginPage = new LoginPage(page)
await loginPage.goto()
await loginPage.login('peter@lustig.de', 'wrongpass')
const toast = new Toasts(page)
await toast.assertErrorToastVisible()
await page.waitForTimeout(50)
})

View File

@ -0,0 +1,11 @@
import { test, expect } from '@playwright/test'
import { LoginPage } from '../pages/LoginPage'
import { FRONTEND_URL } from '../config'
test('valid login', async ({ page }) => {
const loginPage = new LoginPage(page)
await loginPage.goto()
await loginPage.login('peter@lustig.de', 'Aa12345_')
await page.waitForURL(`${FRONTEND_URL}/overview`)
expect(page.url()).toContain('/overview')
})

View File

@ -0,0 +1,41 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@playwright/test@^1.53.1":
version "1.53.1"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.53.1.tgz#3ad5a2ce334b4a78390fd91e0a9d8423c09bc808"
integrity sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==
dependencies:
playwright "1.53.1"
"@types/node@^24.0.7":
version "24.0.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-24.0.7.tgz#ee580f7850c7eabaeef61ef96b8d8c04fdf94f53"
integrity sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw==
dependencies:
undici-types "~7.8.0"
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.53.1:
version "1.53.1"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.53.1.tgz#0b6f7a2006ccb6126ffcc3e3b2fa9efda23b6638"
integrity sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==
playwright@1.53.1:
version "1.53.1"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.53.1.tgz#86fb041b237a6868d163c87c4b9737fd1cac145e"
integrity sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==
dependencies:
playwright-core "1.53.1"
optionalDependencies:
fsevents "2.3.2"
undici-types@~7.8.0:
version "7.8.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.8.0.tgz#de00b85b710c54122e44fbfd911f8d70174cd294"
integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==

1
frontend/.env.test_e2e Normal file
View File

@ -0,0 +1 @@
GRAPHQL_URI=http://127.0.0.1:4000/graphql