Skip to content

Commit 534240e

Browse files
authored
frontend unit+e2e tests (#27)
* frontend unit+e2e tests * deps fix + adding folders with frontend test results to gitignore * ci timeouts added (gha - 60s/10s, local - 30s/5s) * ci fix: - frontend without docker call, directly npm test - backend with setup ci compose * ci tests running in parallel (frontend+backend), fixing of e2e tests * ci - removed backend unit tests job (will add later) - tests fix * base url fix + tests fix (rabbit hints) * error display page + fixes * db name fixes (no more suffix) * error display fix + moved from project name to db name for database * ci: now frontend and backend have completely separate flows * k3s cert in ci * readme small update * added tests and docs about frontend testing
1 parent 30ee844 commit 534240e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+8306
-570
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Setup CI Compose
2+
description: Creates docker-compose.ci.yaml with CI-specific modifications
3+
4+
inputs:
5+
kubeconfig-path:
6+
description: Path to kubeconfig file for cert-generator mount
7+
required: true
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- name: Install yq
13+
shell: bash
14+
run: |
15+
sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.50.1/yq_linux_amd64
16+
sudo chmod +x /usr/local/bin/yq
17+
18+
- name: Create CI compose configuration
19+
shell: bash
20+
env:
21+
KUBECONFIG_PATH: ${{ inputs.kubeconfig-path }}
22+
run: |
23+
cp docker-compose.yaml docker-compose.ci.yaml
24+
25+
# Backend environment variables
26+
yq eval '.services.backend.environment += ["TESTING=true"]' -i docker-compose.ci.yaml
27+
yq eval '.services.backend.environment += ["MONGO_ROOT_USER=root"]' -i docker-compose.ci.yaml
28+
yq eval '.services.backend.environment += ["MONGO_ROOT_PASSWORD=rootpassword"]' -i docker-compose.ci.yaml
29+
yq eval '.services.backend.environment += ["OTEL_SDK_DISABLED=true"]' -i docker-compose.ci.yaml
30+
31+
# Remove hot-reload volume mounts (causes permission issues and slow rebuilds in CI)
32+
yq eval '.services.backend.volumes = [.services.backend.volumes[] | select(. != "./backend:/app")]' -i docker-compose.ci.yaml
33+
yq eval '.services."k8s-worker".volumes = [.services."k8s-worker".volumes[] | select(. != "./backend:/app:ro")]' -i docker-compose.ci.yaml
34+
yq eval '.services."pod-monitor".volumes = [.services."pod-monitor".volumes[] | select(. != "./backend:/app:ro")]' -i docker-compose.ci.yaml
35+
yq eval '.services."result-processor".volumes = [.services."result-processor".volumes[] | select(. != "./backend:/app:ro")]' -i docker-compose.ci.yaml
36+
yq eval '.services.frontend.volumes = [.services.frontend.volumes[] | select(. != "./frontend:/app")]' -i docker-compose.ci.yaml
37+
38+
# Disable Kafka SASL authentication for CI
39+
yq eval 'del(.services.kafka.environment.KAFKA_OPTS)' -i docker-compose.ci.yaml
40+
yq eval 'del(.services.zookeeper.environment.KAFKA_OPTS)' -i docker-compose.ci.yaml
41+
yq eval 'del(.services.zookeeper.environment.ZOOKEEPER_AUTH_PROVIDER_1)' -i docker-compose.ci.yaml
42+
yq eval '.services.kafka.volumes = [.services.kafka.volumes[] | select(. | contains("jaas.conf") | not)]' -i docker-compose.ci.yaml
43+
yq eval '.services.zookeeper.volumes = [.services.zookeeper.volumes[] | select(. | contains("/etc/kafka") | not)]' -i docker-compose.ci.yaml
44+
45+
# Simplify Zookeeper for CI
46+
yq eval '.services.zookeeper.environment.ZOOKEEPER_4LW_COMMANDS_WHITELIST = "ruok,srvr"' -i docker-compose.ci.yaml
47+
yq eval 'del(.services.zookeeper.healthcheck)' -i docker-compose.ci.yaml
48+
yq eval '.services.kafka.depends_on.zookeeper.condition = "service_started"' -i docker-compose.ci.yaml
49+
50+
# Cert-generator CI configuration
51+
yq eval '.services."cert-generator".extra_hosts = ((.services."cert-generator".extra_hosts // []) + ["host.docker.internal:host-gateway"] | unique)' -i docker-compose.ci.yaml
52+
yq eval '.services."cert-generator".environment = ((.services."cert-generator".environment // []) + ["CI=true"] | unique)' -i docker-compose.ci.yaml
53+
yq eval ".services.\"cert-generator\".volumes += [\"${KUBECONFIG_PATH}:/root/.kube/config:ro\"]" -i docker-compose.ci.yaml
54+
55+
echo "Created docker-compose.ci.yaml"

.github/workflows/backend-ci.yml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
name: Backend CI
2+
3+
on:
4+
push:
5+
branches: [main, dev]
6+
paths:
7+
- 'backend/**'
8+
- '.github/workflows/backend-ci.yml'
9+
- 'docker-compose.ci.yaml'
10+
pull_request:
11+
branches: [main, dev]
12+
paths:
13+
- 'backend/**'
14+
- '.github/workflows/backend-ci.yml'
15+
- 'docker-compose.ci.yaml'
16+
workflow_dispatch:
17+
18+
jobs:
19+
integration:
20+
name: Integration Tests
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v6
24+
25+
- name: Set up uv
26+
uses: astral-sh/setup-uv@v7
27+
with:
28+
enable-cache: true
29+
cache-dependency-glob: "backend/uv.lock"
30+
31+
- name: Install Python dependencies
32+
run: |
33+
cd backend
34+
uv python install 3.12
35+
uv sync --frozen
36+
37+
- name: Setup Docker Buildx
38+
uses: docker/setup-buildx-action@v3
39+
40+
- name: Setup Kubernetes (k3s)
41+
run: |
42+
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik --tls-san host.docker.internal" sh -
43+
mkdir -p /home/runner/.kube
44+
sudo k3s kubectl config view --raw > /home/runner/.kube/config
45+
sudo chmod 600 /home/runner/.kube/config
46+
export KUBECONFIG=/home/runner/.kube/config
47+
timeout 90 bash -c 'until sudo k3s kubectl cluster-info; do sleep 5; done'
48+
49+
- name: Create kubeconfig for CI Docker containers
50+
run: |
51+
# Copy real k3s kubeconfig with valid credentials, but change server address
52+
# from 127.0.0.1 to host.docker.internal for Docker container networking
53+
# (k3s was started with --tls-san host.docker.internal so the cert is valid)
54+
sed 's|https://127.0.0.1:6443|https://host.docker.internal:6443|g' \
55+
/home/runner/.kube/config > backend/kubeconfig.yaml
56+
chmod 644 backend/kubeconfig.yaml
57+
58+
- name: Setup CI Compose
59+
uses: ./.github/actions/setup-ci-compose
60+
with:
61+
kubeconfig-path: /home/runner/.kube/config
62+
63+
- name: Build services
64+
uses: docker/bake-action@v6
65+
with:
66+
source: .
67+
files: docker-compose.ci.yaml
68+
load: true
69+
set: |
70+
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
71+
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-main
72+
*.cache-to=type=gha,mode=max,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
73+
*.pull=true
74+
env:
75+
BUILDKIT_PROGRESS: plain
76+
77+
- name: Start services
78+
run: |
79+
docker compose -f docker-compose.ci.yaml up -d --remove-orphans
80+
docker compose -f docker-compose.ci.yaml ps
81+
82+
- name: Wait for backend
83+
run: |
84+
curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:443/api/v1/health/live
85+
docker compose -f docker-compose.ci.yaml ps
86+
kubectl get pods -A -o wide
87+
88+
- name: Run integration tests
89+
timeout-minutes: 10
90+
env:
91+
BACKEND_BASE_URL: https://127.0.0.1:443
92+
MONGO_ROOT_USER: root
93+
MONGO_ROOT_PASSWORD: rootpassword
94+
MONGODB_HOST: 127.0.0.1
95+
MONGODB_PORT: 27017
96+
MONGODB_URL: mongodb://root:[email protected]:27017/?authSource=admin
97+
SCHEMA_SUBJECT_PREFIX: "ci.${{ github.run_id }}."
98+
run: |
99+
cd backend
100+
uv run pytest tests/integration -v --cov=app --cov-branch --cov-report=xml --cov-report=term
101+
102+
- name: Upload coverage to Codecov
103+
uses: codecov/codecov-action@v5
104+
if: always()
105+
with:
106+
token: ${{ secrets.CODECOV_TOKEN }}
107+
files: backend/coverage.xml
108+
flags: backend
109+
name: backend-coverage
110+
slug: HardMax71/Integr8sCode
111+
fail_ci_if_error: false
112+
113+
- name: Collect logs
114+
if: failure()
115+
run: |
116+
mkdir -p logs
117+
docker compose -f docker-compose.ci.yaml logs > logs/docker-compose.log
118+
docker compose -f docker-compose.ci.yaml logs backend > logs/backend.log
119+
docker compose -f docker-compose.ci.yaml logs mongo > logs/mongo.log
120+
kubectl get events --sort-by='.metadata.creationTimestamp' > logs/k8s-events.log 2>&1 || true
121+
kubectl describe pods -A > logs/k8s-describe-pods.log 2>&1 || true
122+
123+
- name: Upload logs
124+
if: failure()
125+
uses: actions/upload-artifact@v6
126+
with:
127+
name: backend-logs
128+
path: logs/

.github/workflows/frontend-ci.yml

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
name: Frontend CI
2+
3+
on:
4+
push:
5+
branches: [main, dev]
6+
paths:
7+
- 'frontend/**'
8+
- '.github/workflows/frontend-ci.yml'
9+
- 'docker-compose.ci.yaml'
10+
pull_request:
11+
branches: [main, dev]
12+
paths:
13+
- 'frontend/**'
14+
- '.github/workflows/frontend-ci.yml'
15+
- 'docker-compose.ci.yaml'
16+
workflow_dispatch:
17+
18+
jobs:
19+
unit:
20+
name: Unit Tests
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v6
24+
25+
- name: Setup Node.js
26+
uses: actions/setup-node@v4
27+
with:
28+
node-version: '22'
29+
cache: 'npm'
30+
cache-dependency-path: frontend/package-lock.json
31+
32+
- name: Install dependencies
33+
working-directory: frontend
34+
run: npm ci
35+
36+
- name: Run unit tests with coverage
37+
working-directory: frontend
38+
run: npm run test:coverage
39+
40+
- name: Upload coverage to Codecov
41+
uses: codecov/codecov-action@v5
42+
with:
43+
token: ${{ secrets.CODECOV_TOKEN }}
44+
files: frontend/coverage/lcov.info
45+
flags: frontend
46+
name: frontend-coverage
47+
slug: HardMax71/Integr8sCode
48+
fail_ci_if_error: false
49+
50+
e2e:
51+
name: E2E Tests
52+
needs: unit
53+
runs-on: ubuntu-latest
54+
steps:
55+
- uses: actions/checkout@v6
56+
57+
- name: Setup Node.js
58+
uses: actions/setup-node@v4
59+
with:
60+
node-version: '22'
61+
cache: 'npm'
62+
cache-dependency-path: frontend/package-lock.json
63+
64+
- name: Install dependencies
65+
working-directory: frontend
66+
run: npm ci
67+
68+
- name: Install Playwright browsers
69+
working-directory: frontend
70+
run: npx playwright install chromium
71+
72+
- name: Setup Docker Buildx
73+
uses: docker/setup-buildx-action@v3
74+
75+
- name: Setup Kubernetes (k3s)
76+
run: |
77+
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik --tls-san host.docker.internal" sh -
78+
mkdir -p /home/runner/.kube
79+
sudo k3s kubectl config view --raw > /home/runner/.kube/config
80+
sudo chmod 600 /home/runner/.kube/config
81+
export KUBECONFIG=/home/runner/.kube/config
82+
timeout 90 bash -c 'until sudo k3s kubectl cluster-info; do sleep 5; done'
83+
84+
- name: Create kubeconfig for CI
85+
run: |
86+
cat > backend/kubeconfig.yaml <<EOF
87+
apiVersion: v1
88+
kind: Config
89+
clusters:
90+
- name: ci-cluster
91+
cluster:
92+
server: https://host.docker.internal:6443
93+
insecure-skip-tls-verify: true
94+
users:
95+
- name: ci-user
96+
user:
97+
token: "ci-token"
98+
contexts:
99+
- name: ci
100+
context:
101+
cluster: ci-cluster
102+
user: ci-user
103+
current-context: ci
104+
EOF
105+
106+
- name: Setup CI Compose
107+
uses: ./.github/actions/setup-ci-compose
108+
with:
109+
kubeconfig-path: /home/runner/.kube/config
110+
111+
- name: Build services
112+
uses: docker/bake-action@v6
113+
with:
114+
source: .
115+
files: docker-compose.ci.yaml
116+
load: true
117+
set: |
118+
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
119+
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-main
120+
*.cache-to=type=gha,mode=max,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
121+
*.pull=true
122+
env:
123+
BUILDKIT_PROGRESS: plain
124+
125+
- name: Start services
126+
run: |
127+
docker compose -f docker-compose.ci.yaml up -d --remove-orphans
128+
docker compose -f docker-compose.ci.yaml ps
129+
130+
- name: Wait for services
131+
run: |
132+
echo "Waiting for backend..."
133+
curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:443/api/v1/health/live
134+
echo "Waiting for frontend..."
135+
curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:5001/
136+
137+
- name: Seed test users
138+
run: |
139+
docker compose -f docker-compose.ci.yaml exec -T backend uv run python scripts/seed_users.py
140+
141+
- name: Run E2E tests
142+
working-directory: frontend
143+
env:
144+
CI: true
145+
run: npx playwright test --reporter=html
146+
147+
- name: Upload Playwright report
148+
uses: actions/upload-artifact@v6
149+
if: always()
150+
with:
151+
name: playwright-report
152+
path: frontend/playwright-report/
153+
154+
- name: Collect logs
155+
if: failure()
156+
run: |
157+
mkdir -p logs
158+
docker compose -f docker-compose.ci.yaml logs > logs/docker-compose.log
159+
docker compose -f docker-compose.ci.yaml logs backend > logs/backend.log
160+
docker compose -f docker-compose.ci.yaml logs frontend > logs/frontend.log
161+
162+
- name: Upload logs
163+
if: failure()
164+
uses: actions/upload-artifact@v6
165+
with:
166+
name: frontend-e2e-logs
167+
path: logs/

0 commit comments

Comments
 (0)