🧑‍💻(docker) split frontend to another file

This commit aims at improving the user experience:
- Use a dedicated `Dockerfile` for the frontend
- Run the backend and frontend in "watch"/dev mode in Docker
- Do not start all Docker instances for small tasks
This commit is contained in:
Quentin BEY
2025-06-12 15:10:37 +02:00
parent 4dfd682cb6
commit 213656fc2e
21 changed files with 257 additions and 132 deletions

View File

@@ -40,7 +40,7 @@ jobs:
name: Run trivy scan (frontend) name: Run trivy scan (frontend)
uses: numerique-gouv/action-trivy-cache@main uses: numerique-gouv/action-trivy-cache@main
with: with:
docker-build-args: '--target frontend-production -f Dockerfile' docker-build-args: '--target frontend-production -f src/frontend/Dockerfile'
docker-image-name: 'docker.io/lasuite/people-frontend:${{ github.sha }}' docker-image-name: 'docker.io/lasuite/people-frontend:${{ github.sha }}'
build-and-push-backend: build-and-push-backend:
@@ -105,6 +105,7 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
context: . context: .
file: ./src/frontend/Dockerfile
target: frontend-production target: frontend-production
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000 build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}

View File

@@ -167,6 +167,8 @@ jobs:
COMPOSE_DOCKER_CLI_BUILD: 1 COMPOSE_DOCKER_CLI_BUILD: 1
run: | run: |
docker compose build --pull --build-arg BUILDKIT_INLINE_CACHE=1 docker compose build --pull --build-arg BUILDKIT_INLINE_CACHE=1
make update-keycloak-realm-app
make add-dev-rsa-private-key-to-env
make run make run
- name: Apply DRF migrations - name: Apply DRF migrations
@@ -177,10 +179,6 @@ jobs:
run: | run: |
make demo FLUSH_ARGS='--no-input' make demo FLUSH_ARGS='--no-input'
- name: Setup Dimail DB
run: |
make dimail-setup-db
- name: Run e2e tests - name: Run e2e tests
run: cd src/frontend/ && yarn e2e:test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} run: cd src/frontend/ && yarn e2e:test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}

View File

@@ -12,6 +12,10 @@ and this project adheres to
- ✨(resource-server) add SCIM /Me endpoint #895 - ✨(resource-server) add SCIM /Me endpoint #895
### Changed
- 🧑‍💻(docker) split frontend to another file #924
## [1.17.0] - 2025-06-11 ## [1.17.0] - 2025-06-11
### Added ### Added

View File

@@ -10,61 +10,6 @@ RUN python -m pip install --upgrade pip setuptools
RUN apk update && \ RUN apk update && \
apk upgrade apk upgrade
### ---- Front-end dependencies image ----
FROM node:20 AS frontend-deps
WORKDIR /deps
COPY ./src/frontend/package.json ./package.json
COPY ./src/frontend/yarn.lock ./yarn.lock
COPY ./src/frontend/apps/desk/package.json ./apps/desk/package.json
COPY ./src/frontend/packages/i18n/package.json ./packages/i18n/package.json
COPY ./src/frontend/packages/eslint-config-people/package.json ./packages/eslint-config-people/package.json
RUN yarn --frozen-lockfile
### ---- Front-end builder dev image ----
FROM node:20 AS frontend-builder-dev
WORKDIR /builder
COPY --from=frontend-deps /deps/node_modules ./node_modules
COPY ./src/frontend .
WORKDIR ./apps/desk
### ---- Front-end builder image ----
FROM frontend-builder-dev AS frontend-builder
RUN yarn build
# ---- Front-end image ----
FROM nginxinc/nginx-unprivileged:1.27-alpine AS frontend-production
USER root
RUN apk update && apk upgrade libssl3 libcrypto3 libxml2
USER nginx
# Un-privileged user running the application
ARG DOCKER_USER
USER ${DOCKER_USER}
COPY --from=frontend-builder \
/builder/apps/desk/out \
/usr/share/nginx/html
COPY ./src/frontend/apps/desk/conf/default.conf /etc/nginx/conf.d
# Copy entrypoint
COPY ./docker/files/usr/local/bin/entrypoint /usr/local/bin/entrypoint
ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
CMD ["nginx", "-g", "daemon off;"]
# ---- Back-end builder image ---- # ---- Back-end builder image ----
FROM base AS back-builder FROM base AS back-builder

View File

@@ -41,11 +41,9 @@ DOCKER_USER = $(DOCKER_UID):$(DOCKER_GID)
COMPOSE = DOCKER_USER=$(DOCKER_USER) docker compose COMPOSE = DOCKER_USER=$(DOCKER_USER) docker compose
COMPOSE_EXEC = $(COMPOSE) exec COMPOSE_EXEC = $(COMPOSE) exec
COMPOSE_EXEC_APP = $(COMPOSE_EXEC) app-dev COMPOSE_EXEC_APP = $(COMPOSE_EXEC) app-dev
COMPOSE_RUN = $(COMPOSE) run --rm COMPOSE_RUN = $(COMPOSE) run --rm --no-deps
COMPOSE_RUN_APP = $(COMPOSE_RUN) app-dev COMPOSE_RUN_APP = $(COMPOSE_RUN) app-dev
COMPOSE_RUN_CROWDIN = $(COMPOSE_RUN) crowdin crowdin COMPOSE_RUN_CROWDIN = $(COMPOSE_RUN) crowdin crowdin
WAIT_DB = @$(COMPOSE_RUN) dockerize -wait tcp://$(DB_HOST):$(DB_PORT) -timeout 60s
WAIT_KC_DB = $(COMPOSE_RUN) dockerize -wait tcp://kc_postgresql:5432 -timeout 60s
# -- Backend # -- Backend
MANAGE = $(COMPOSE_RUN_APP) python manage.py MANAGE = $(COMPOSE_RUN_APP) python manage.py
@@ -78,19 +76,33 @@ create-env-files: \
env.d/development/kc_postgresql env.d/development/kc_postgresql
.PHONY: create-env-files .PHONY: create-env-files
add-dev-rsa-private-key-to-env: ## Add a generated RSA private key to the env file
@echo "Generating RSA private key PEM for development..."
@mkdir -p env.d/development/rsa
@openssl genrsa -out env.d/development/rsa/private.pem 2048
@echo -n "\nOAUTH2_PROVIDER_OIDC_RSA_PRIVATE_KEY=\"" >> env.d/development/common
@openssl rsa -in env.d/development/rsa/private.pem -outform PEM >> env.d/development/common
@echo "\"" >> env.d/development/common
@rm -rf env.d/development/rsa
.PHONY: add-dev-rsa-private-key-to-env
update-keycloak-realm-app: ## Create the Keycloak realm for the project
@echo "$(BOLD)Creating Keycloak realm for 'app'$(RESET)"
@sed -i 's|http://app-dev:8000|http://app:8000|g' ./docker/auth/realm.json
.PHONY: update-keycloak-realm-app
bootstrap: ## Prepare Docker images for the project and install frontend dependencies bootstrap: ## Prepare Docker images for the project and install frontend dependencies
bootstrap: \ bootstrap: \
data/media \ data/media \
data/static \ data/static \
create-env-files \ create-env-files \
build \ build \
run \ run-dev \
migrate \ migrate \
back-i18n-compile \ back-i18n-compile \
mails-install \ mails-install \
mails-build \ mails-build \
dimail-setup-db \ dimail-setup-db
install-front-desk
.PHONY: bootstrap .PHONY: bootstrap
# -- Docker/compose # -- Docker/compose
@@ -106,19 +118,14 @@ logs: ## display app-dev logs (follow mode)
@$(COMPOSE) logs -f app-dev @$(COMPOSE) logs -f app-dev
.PHONY: logs .PHONY: logs
run: ## start the wsgi (production) and development server run: ## start the wsgi (production) and servers with production Docker images
@$(COMPOSE) up --force-recreate -d nginx @$(COMPOSE) up --force-recreate --detach app frontend celery celery-beat nginx maildev
@$(COMPOSE) up --force-recreate -d app-dev
@$(COMPOSE) up --force-recreate -d celery-dev
@$(COMPOSE) up --force-recreate -d celery-beat-dev
@$(COMPOSE) up --force-recreate -d flower-dev
@$(COMPOSE) up --force-recreate -d keycloak
@$(COMPOSE) up -d dimail
@echo "Wait for postgresql to be up..."
@$(WAIT_KC_DB)
@$(WAIT_DB)
.PHONY: run .PHONY: run
run-dev: ## start the servers in development mode (watch) Docker images
@$(COMPOSE) up --force-recreate --detach app-dev frontend-dev celery-dev celery-beat-dev nginx maildev
.PHONY: run-dev
status: ## an alias for "docker compose ps" status: ## an alias for "docker compose ps"
@$(COMPOSE) ps @$(COMPOSE) ps
.PHONY: status .PHONY: status
@@ -187,22 +194,16 @@ test-coverage: ## compute, display and save test coverage
makemigrations: ## run django makemigrations for the people project. makemigrations: ## run django makemigrations for the people project.
@echo "$(BOLD)Running makemigrations$(RESET)" @echo "$(BOLD)Running makemigrations$(RESET)"
@$(COMPOSE) up -d postgresql
@$(WAIT_DB)
@$(MANAGE) makemigrations $(ARGS) @$(MANAGE) makemigrations $(ARGS)
.PHONY: makemigrations .PHONY: makemigrations
migrate: ## run django migrations for the people project. migrate: ## run django migrations for the people project.
@echo "$(BOLD)Running migrations$(RESET)" @echo "$(BOLD)Running migrations$(RESET)"
@$(COMPOSE) up -d postgresql
@$(WAIT_DB)
@$(MANAGE) migrate $(ARGS) @$(MANAGE) migrate $(ARGS)
.PHONY: migrate .PHONY: migrate
showmigrations: ## run django showmigrations for the people project. showmigrations: ## run django showmigrations for the people project.
@echo "$(BOLD)Running showmigrations$(RESET)" @echo "$(BOLD)Running showmigrations$(RESET)"
@$(COMPOSE) up -d postgresql
@$(WAIT_DB)
@$(MANAGE) showmigrations $(ARGS) @$(MANAGE) showmigrations $(ARGS)
.PHONY: showmigrations .PHONY: showmigrations

View File

@@ -33,7 +33,7 @@ The easiest way to start working on the project is to use GNU Make:
$ make bootstrap $ make bootstrap
``` ```
This command builds the `app` container, installs dependencies, performs This command builds the `app-dev` container, installs dependencies, performs
database migrations and compile translations. It's a good idea to use this database migrations and compile translations. It's a good idea to use this
command each time you are pulling code from the project repository to avoid command each time you are pulling code from the project repository to avoid
dependency-related or migration-related issues. dependency-related or migration-related issues.
@@ -46,6 +46,12 @@ Note that if you need to run them afterward, you can use the eponym Make rule:
$ make run $ make run
``` ```
or if you want to run them in development mode (with live reloading):
```bash
$ make run-dev
```
You can check all available Make rules using: You can check all available Make rules using:
```bash ```bash

View File

@@ -64,6 +64,23 @@ function _dc_run() {
_docker_compose run --rm $user_args "$@" _docker_compose run --rm $user_args "$@"
} }
# _dc_run_no_deps: wrap docker compose run command without dependencies
#
# usage: _dc_run_no_deps [options] [ARGS...]
#
# options: docker compose run command options
# ARGS : docker compose run command arguments
function _dc_run_no_deps() {
_set_user
user_args="--user=$USER_ID"
if [ -z $USER_ID ]; then
user_args=""
fi
_docker_compose run --no-deps --rm $user_args "$@"
}
# _dc_exec: wrap docker compose exec command # _dc_exec: wrap docker compose exec command
# #
# usage: _dc_exec [options] [ARGS...] # usage: _dc_exec [options] [ARGS...]

View File

@@ -35,4 +35,4 @@ fi
# Fix docker vs local path when project sources are mounted as a volume # Fix docker vs local path when project sources are mounted as a volume
read -ra paths <<< "$(echo "${paths[@]}" | sed "s|src/backend/||g")" read -ra paths <<< "$(echo "${paths[@]}" | sed "s|src/backend/||g")"
_dc_run app-dev pylint "${paths[@]}" "${args[@]}" _dc_run_no_deps app-dev pylint "${paths[@]}" "${args[@]}"

View File

@@ -6,6 +6,11 @@ services:
- env.d/development/postgresql - env.d/development/postgresql
ports: ports:
- "15432:5432" - "15432:5432"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ]
interval: 1s
timeout: 2s
retries: 300
redis: redis:
image: redis:5 image: redis:5
@@ -23,6 +28,7 @@ services:
DOCKER_USER: ${DOCKER_USER:-1000} DOCKER_USER: ${DOCKER_USER:-1000}
user: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000}
image: people:backend-development image: people:backend-development
pull_policy: never
environment: environment:
- PYLINTHOME=/app/.pylint.d - PYLINTHOME=/app/.pylint.d
- DJANGO_CONFIGURATION=Development - DJANGO_CONFIGURATION=Development
@@ -37,10 +43,68 @@ services:
- ./data/media:/data/media - ./data/media:/data/media
- ./data/static:/data/static - ./data/static:/data/static
depends_on: depends_on:
- dimail postgresql:
- postgresql condition: service_healthy
- maildev restart: true
- redis dimail:
condition: service_started
maildev:
condition: service_started
redis:
condition: service_started
frontend-dev:
user: "${DOCKER_USER:-1000}"
build:
context: .
dockerfile: ./src/frontend/Dockerfile
target: frontend-dev
image: people:frontend-development
pull_policy: never
volumes:
- ./src/frontend:/home/frontend
- /home/frontend/node_modules
- /home/frontend/apps/desk/node_modules
ports:
- "3000:3000"
app:
build:
context: .
target: backend-production
args:
DOCKER_USER: ${DOCKER_USER:-1000}
user: ${DOCKER_USER:-1000}
image: people:backend-production
environment:
- DJANGO_CONFIGURATION=Development
env_file:
- env.d/development/common
- env.d/development/france
- env.d/development/postgresql
ports:
- "8071:8000"
volumes:
- ./data/media:/data/media
depends_on:
postgresql:
condition: service_healthy
restart: true
redis:
condition: service_started
frontend:
user: "${DOCKER_USER:-1000}"
build:
context: .
dockerfile: ./src/frontend/Dockerfile
target: frontend-production
args:
API_ORIGIN: "http://localhost:8071"
image: people:frontend-production
pull_policy: build
ports:
- "3000:3000"
celery-dev: celery-dev:
user: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000}
@@ -56,7 +120,11 @@ services:
- ./data/media:/data/media - ./data/media:/data/media
- ./data/static:/data/static - ./data/static:/data/static
depends_on: depends_on:
- app-dev postgresql:
condition: service_healthy
restart: true
app-dev:
condition: service_started
celery-beat-dev: celery-beat-dev:
user: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000}
@@ -72,26 +140,9 @@ services:
- ./data/media:/data/media - ./data/media:/data/media
- ./data/static:/data/static - ./data/static:/data/static
depends_on: depends_on:
- app-dev postgresql:
condition: service_healthy
app: restart: true
build:
context: .
target: backend-production
args:
DOCKER_USER: ${DOCKER_USER:-1000}
user: ${DOCKER_USER:-1000}
image: people:backend-production
environment:
- DJANGO_CONFIGURATION=Demo
env_file:
- env.d/development/common
- env.d/development/postgresql
volumes:
- ./data/media:/data/media
depends_on:
- postgresql
- redis
celery: celery:
user: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000}
@@ -103,7 +154,29 @@ services:
- env.d/development/common - env.d/development/common
- env.d/development/postgresql - env.d/development/postgresql
depends_on: depends_on:
- app postgresql:
condition: service_healthy
restart: true
app:
condition: service_started
celery-beat:
user: ${DOCKER_USER:-1000}
image: people:backend-production
command: ["celery", "-A", "people.celery_app", "beat", "-l", "INFO"]
environment:
- DJANGO_CONFIGURATION=Demo
env_file:
- env.d/development/common
- env.d/development/postgresql
volumes:
- ./src/backend:/app
- ./data/media:/data/media
- ./data/static:/data/static
depends_on:
postgresql:
condition: service_healthy
restart: true
nginx: nginx:
image: nginx:1.25 image: nginx:1.25
@@ -112,12 +185,9 @@ services:
volumes: volumes:
- ./docker/files/etc/nginx/conf.d:/etc/nginx/conf.d:ro - ./docker/files/etc/nginx/conf.d:/etc/nginx/conf.d:ro
depends_on: depends_on:
- app keycloak:
- keycloak condition: service_healthy
restart: true
dockerize:
image: jwilder/dockerize
platform: linux/x86_64
crowdin: crowdin:
image: crowdin/cli:4.6.1 image: crowdin/cli:4.6.1
@@ -142,6 +212,11 @@ services:
- "5433:5432" - "5433:5432"
env_file: env_file:
- env.d/development/kc_postgresql - env.d/development/kc_postgresql
healthcheck:
test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ]
interval: 1s
timeout: 2s
retries: 300
keycloak: keycloak:
image: quay.io/keycloak/keycloak:20.0.1 image: quay.io/keycloak/keycloak:20.0.1
@@ -158,6 +233,8 @@ services:
- --hostname-admin-url=http://localhost:8083/ - --hostname-admin-url=http://localhost:8083/
- --hostname-strict=false - --hostname-strict=false
- --hostname-strict-https=false - --hostname-strict-https=false
- --health-enabled=true
- --metrics-enabled=true
environment: environment:
KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin KEYCLOAK_ADMIN_PASSWORD: admin
@@ -168,10 +245,17 @@ services:
KC_DB_USERNAME: people KC_DB_USERNAME: people
KC_DB_SCHEMA: public KC_DB_SCHEMA: public
PROXY_ADDRESS_FORWARDING: 'true' PROXY_ADDRESS_FORWARDING: 'true'
healthcheck:
test: [ "CMD", "curl", "--head", "-fsS", "http://localhost:8080/health/ready" ]
interval: 1s
timeout: 2s
retries: 300
ports: ports:
- "8080:8080" - "8080:8080"
depends_on: depends_on:
- kc_postgresql kc_postgresql:
condition: service_healthy
restart: true
dimail: dimail:
entrypoint: /opt/dimail-api/start-dev.sh entrypoint: /opt/dimail-api/start-dev.sh

View File

@@ -26,7 +26,7 @@
"oauth2DeviceCodeLifespan": 600, "oauth2DeviceCodeLifespan": 600,
"oauth2DevicePollingInterval": 5, "oauth2DevicePollingInterval": 5,
"enabled": true, "enabled": true,
"sslRequired": "external", "sslRequired": "none",
"registrationAllowed": true, "registrationAllowed": true,
"registrationEmailAsUsername": false, "registrationEmailAsUsername": false,
"rememberMe": true, "rememberMe": true,

View File

@@ -3,6 +3,7 @@ DJANGO_ALLOWED_HOSTS=*
DJANGO_SECRET_KEY=ThisIsAnExampleKeyForDevPurposeOnly DJANGO_SECRET_KEY=ThisIsAnExampleKeyForDevPurposeOnly
DJANGO_SETTINGS_MODULE=people.settings DJANGO_SETTINGS_MODULE=people.settings
DJANGO_SUPERUSER_PASSWORD=admin DJANGO_SUPERUSER_PASSWORD=admin
DJANGO_CORS_ALLOWED_ORIGINS=http://localhost:3000
# Python # Python
PYTHONPATH=/app PYTHONPATH=/app

View File

@@ -2,7 +2,9 @@
SUSTAINED_THROTTLE_RATES="200/hour" SUSTAINED_THROTTLE_RATES="200/hour"
BURST_THROTTLE_RATES="200/minute" BURST_THROTTLE_RATES="200/minute"
OAUTH2_PROVIDER_OIDC_ENABLED = True OIDC_ORGANIZATION_REGISTRATION_ID_FIELD="siret"
OAUTH2_PROVIDER_VALIDATOR_CLASS: "mailbox_oauth2.validators.ProConnectValidator"
OAUTH2_PROVIDER_OIDC_ENABLED=True
OAUTH2_PROVIDER_VALIDATOR_CLASS="mailbox_oauth2.validators.ProConnectValidator"
INSTALLED_PLUGINS=plugins.la_suite INSTALLED_PLUGINS=plugins.la_suite

View File

@@ -34,6 +34,7 @@ dependencies = [
"django-configurations==2.5.1", "django-configurations==2.5.1",
"django-cors-headers==4.7.0", "django-cors-headers==4.7.0",
"django-countries==7.6.1", "django-countries==7.6.1",
"django-extensions==4.1",
"django-lasuite==0.0.9", "django-lasuite==0.0.9",
"django-oauth-toolkit==3.0.1", "django-oauth-toolkit==3.0.1",
"django-parler==2.3", "django-parler==2.3",
@@ -70,7 +71,6 @@ dependencies = [
[project.optional-dependencies] [project.optional-dependencies]
dev = [ dev = [
"django-extensions==4.1",
"drf-spectacular-sidecar==2025.6.1", "drf-spectacular-sidecar==2025.6.1",
"ipdb==0.13.13", "ipdb==0.13.13",
"ipython==9.3.0", "ipython==9.3.0",

63
src/frontend/Dockerfile Normal file
View File

@@ -0,0 +1,63 @@
FROM node:22-alpine AS frontend-deps
# Upgrade system packages to install security updates
RUN apk update && \
apk upgrade && \
rm -rf /var/cache/apk/*
WORKDIR /home/frontend/
COPY ./src/frontend/package.json ./package.json
COPY ./src/frontend/yarn.lock ./yarn.lock
COPY ./src/frontend/apps/desk/package.json ./apps/desk/package.json
COPY ./src/frontend/packages/i18n/package.json ./packages/i18n/package.json
COPY ./src/frontend/packages/eslint-config-people/package.json ./packages/eslint-config-people/package.json
RUN yarn install --frozen-lockfile
COPY .dockerignore ./.dockerignore
COPY ./src/frontend/.prettierrc.js ./.prettierrc.js
COPY ./src/frontend/packages/eslint-config-people ./packages/eslint-config-people
COPY ./src/frontend/apps/desk ./apps/desk
### ---- Front-end builder image ----
FROM frontend-deps AS frontend-base
WORKDIR /home/frontend/apps/desk
### ---- Front-end builder dev image ----
FROM frontend-deps AS frontend-dev
WORKDIR /home/frontend/apps/desk
EXPOSE 3000
CMD [ "yarn", "dev"]
FROM frontend-base AS frontend-builder
WORKDIR /home/frontend/apps/desk
ARG API_ORIGIN
ENV NEXT_PUBLIC_API_ORIGIN=${API_ORIGIN}
RUN yarn build
# ---- Front-end image ----
FROM nginxinc/nginx-unprivileged:alpine3.21 AS frontend-production
# Un-privileged user running the application
ARG DOCKER_USER
USER ${DOCKER_USER}
COPY --from=frontend-builder \
/home/frontend/apps/desk/out \
/usr/share/nginx/html
COPY ./src/frontend/apps/desk/conf/default.conf /etc/nginx/conf.d
COPY ./docker/files/usr/local/bin/entrypoint /usr/local/bin/entrypoint
ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,4 +1,5 @@
server { server {
listen 3000;
listen 8080; listen 8080;
server_name localhost; server_name localhost;
server_tokens off; server_tokens off;

View File

@@ -97,6 +97,7 @@ test.describe('Mail domain', () => {
}); });
await page.goto('/mail-domains/unknown-domain.fr'); await page.goto('/mail-domains/unknown-domain.fr');
await page.waitForURL('/404/');
await expect( await expect(
page.getByText( page.getByText(
'It seems that the page you are looking for does not exist or cannot be displayed correctly.', 'It seems that the page you are looking for does not exist or cannot be displayed correctly.',

View File

@@ -101,6 +101,8 @@ test.describe('Add Mail Domains', () => {
test('checks 404 on mail-domains/[slug] page', async ({ page }) => { test('checks 404 on mail-domains/[slug] page', async ({ page }) => {
await page.goto('/mail-domains/unknown-domain'); await page.goto('/mail-domains/unknown-domain');
await page.waitForURL('/404/');
await expect( await expect(
page.getByText( page.getByText(
'It seems that the page you are looking for does not exist or cannot be displayed correctly.', 'It seems that the page you are looking for does not exist or cannot be displayed correctly.',

View File

@@ -83,6 +83,7 @@ test.describe('Teams Create', () => {
test('checks 404 on teams/[id] page', async ({ page }) => { test('checks 404 on teams/[id] page', async ({ page }) => {
await page.goto('/teams/some-unknown-team'); await page.goto('/teams/some-unknown-team');
await page.waitForURL('/404/');
await expect( await expect(
page.getByText( page.getByText(
'It seems that the page you are looking for does not exist or cannot be displayed correctly.', 'It seems that the page you are looking for does not exist or cannot be displayed correctly.',

View File

@@ -32,12 +32,10 @@ export default defineConfig({
}, },
webServer: { webServer: {
command: `cd ../.. && yarn app:${ command: !process.env.CI ? `cd ../.. && yarn app:dev --port ${PORT}` : '',
process.env.CI ? 'start -p ' : 'dev --port '
} ${PORT}`,
url: baseURL, url: baseURL,
timeout: 120 * 1000, timeout: 120 * 1000,
reuseExistingServer: !process.env.CI, reuseExistingServer: true,
}, },
/* Configure projects for major browsers */ /* Configure projects for major browsers */