Skip to content

Commit 97cb7c7

Browse files
wuhan005github-advanced-security[bot]Copilot
authored
test: e2e test (#72)
* test: add db test Signed-off-by: E99p1ant <i@github.red> * add codecov Signed-off-by: E99p1ant <i@github.red> * init e2e Signed-off-by: E99p1ant <i@github.red> * Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * update minio image Signed-off-by: E99p1ant <i@github.red> * fix minio Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * fix test Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * debug Signed-off-by: E99p1ant <i@github.red> * update test Signed-off-by: E99p1ant <i@github.red> * fix test Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * update minio timeout Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * update Signed-off-by: E99p1ant <i@github.red> * create minio bucket Signed-off-by: E99p1ant <i@github.red> * update put object Signed-off-by: E99p1ant <i@github.red> * coverage Signed-off-by: E99p1ant <i@github.red> * update coverage Signed-off-by: E99p1ant <i@github.red> * Update web/src/utils/recaptcha.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * update Signed-off-by: E99p1ant <i@github.red> --------- Signed-off-by: E99p1ant <i@github.red> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ab9ab3c commit 97cb7c7

24 files changed

Lines changed: 1003 additions & 61 deletions

.github/workflows/e2e.yml

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
name: E2E Tests
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
e2e:
14+
name: Run E2E Tests
15+
runs-on: ubuntu-latest
16+
17+
services:
18+
postgres:
19+
image: postgres:16
20+
env:
21+
POSTGRES_USER: nekobox
22+
POSTGRES_PASSWORD: nekobox
23+
POSTGRES_DB: nekobox_e2e
24+
ports:
25+
- 5432:5432
26+
options: >-
27+
--health-cmd pg_isready
28+
--health-interval 10s
29+
--health-timeout 5s
30+
--health-retries 5
31+
32+
redis:
33+
image: redis:7
34+
ports:
35+
- 6379:6379
36+
options: >-
37+
--health-cmd "redis-cli ping"
38+
--health-interval 10s
39+
--health-timeout 5s
40+
--health-retries 5
41+
42+
mailhog:
43+
image: mailhog/mailhog:latest
44+
ports:
45+
- 1025:1025
46+
- 8025:8025
47+
options: >-
48+
--health-cmd "wget -qO- http://localhost:8025/api/v2/messages || exit 1"
49+
--health-interval 5s
50+
--health-timeout 3s
51+
--health-retries 10
52+
53+
steps:
54+
- name: Checkout code
55+
uses: actions/checkout@v4
56+
57+
- name: Set up Go
58+
uses: actions/setup-go@v5
59+
with:
60+
go-version-file: go.mod
61+
62+
- name: Set up Node.js
63+
uses: actions/setup-node@v4
64+
with:
65+
node-version: '20'
66+
67+
- name: Set up pnpm
68+
uses: pnpm/action-setup@v4
69+
with:
70+
version: latest
71+
72+
- name: Start MinIO (pgsty/minio)
73+
run: |
74+
docker run -d \
75+
--name minio \
76+
--network host \
77+
-e MINIO_ROOT_USER=minioadmin \
78+
-e MINIO_ROOT_PASSWORD=minioadmin \
79+
pgsty/minio \
80+
server /data --console-address ":9001"
81+
82+
- name: Wait for MinIO
83+
run: |
84+
echo "Waiting for MinIO S3 API to be ready..."
85+
for i in $(seq 1 60); do
86+
if curl -sf http://localhost:9000/minio/health/live > /dev/null 2>&1; then
87+
echo "MinIO is ready (health check passed)"
88+
sleep 2
89+
exit 0
90+
fi
91+
echo "Waiting for MinIO ($i/60)..."
92+
sleep 2
93+
done
94+
echo "MinIO did not become ready in time"
95+
docker logs minio || true
96+
exit 1
97+
98+
- name: Create MinIO bucket
99+
run: |
100+
curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc -o ./mc
101+
chmod +x ./mc
102+
./mc alias set local http://localhost:9000 minioadmin minioadmin
103+
./mc mb --ignore-existing local/nekobox-e2e
104+
./mc ls local/nekobox-e2e
105+
echo "minio-smoke" > /tmp/minio-smoke.txt
106+
./mc cp /tmp/minio-smoke.txt local/nekobox-e2e/health/smoke.txt
107+
./mc stat local/nekobox-e2e/health/smoke.txt
108+
109+
# ── Backend ────────────────────────────────────────────────────────────
110+
111+
- name: Build backend
112+
run: |
113+
COVERPKG=$(go list ./... | paste -sd "," -)
114+
go build -cover -covermode=atomic -coverpkg="$COVERPKG" -o ./nekobox-server ./cmd
115+
116+
- name: Start backend (port 8080)
117+
run: |
118+
mkdir -p coverage/backend
119+
GOCOVERDIR=$PWD/coverage/backend NEKOBOX_CONFIG_PATH=conf/app.e2e.ini ./nekobox-server web &
120+
echo $! > /tmp/nekobox-server.pid
121+
122+
# ── Frontend ───────────────────────────────────────────────────────────
123+
124+
- name: Install frontend dependencies
125+
working-directory: web
126+
run: pnpm install
127+
128+
- name: Start frontend dev server (port 3000)
129+
working-directory: web
130+
run: pnpm dev:e2e &
131+
env:
132+
VITE_EXTERNAL_URL: http://localhost:3000
133+
134+
- name: Wait for frontend to be ready
135+
run: |
136+
for i in $(seq 1 30); do
137+
if curl -sf http://localhost:3000 > /dev/null 2>&1; then
138+
echo "Frontend is up!"
139+
break
140+
fi
141+
echo "Waiting for frontend ($i/30)..."
142+
sleep 2
143+
done
144+
145+
# ── Playwright ─────────────────────────────────────────────────────────
146+
147+
- name: Install Playwright dependencies
148+
working-directory: e2e
149+
run: npm install
150+
151+
- name: Install Playwright browsers
152+
working-directory: e2e
153+
run: npx playwright install --with-deps chromium
154+
155+
- name: Run Playwright E2E tests
156+
working-directory: e2e
157+
run: npx playwright test
158+
env:
159+
E2E_BASE_URL: http://localhost:3000
160+
E2E_MAILHOG_URL: http://localhost:8025
161+
162+
- name: Stop backend and generate coverage.txt
163+
if: always()
164+
run: |
165+
if [ -f /tmp/nekobox-server.pid ]; then
166+
BACKEND_PID=$(cat /tmp/nekobox-server.pid)
167+
if kill -0 "$BACKEND_PID" 2>/dev/null; then
168+
kill "$BACKEND_PID"
169+
for i in $(seq 1 20); do
170+
if ! kill -0 "$BACKEND_PID" 2>/dev/null; then
171+
break
172+
fi
173+
sleep 1
174+
done
175+
if kill -0 "$BACKEND_PID" 2>/dev/null; then
176+
kill -9 "$BACKEND_PID" || true
177+
fi
178+
fi
179+
fi
180+
181+
mkdir -p coverage
182+
if [ -d coverage/backend ] && [ -n "$(ls -A coverage/backend)" ]; then
183+
go tool covdata textfmt -i=coverage/backend -o=coverage/coverage.txt
184+
echo "Route coverage entries:"
185+
grep 'internal/route/' coverage/coverage.txt | head -n 20 || true
186+
187+
if ! grep -q 'internal/route/' coverage/coverage.txt; then
188+
echo "::error::No internal/route coverage found in coverage/coverage.txt"
189+
exit 1
190+
fi
191+
else
192+
echo "No backend coverage data found" > coverage/coverage.txt
193+
echo "::error::No backend coverage data found in coverage/backend"
194+
exit 1
195+
fi
196+
197+
- name: Upload Playwright report
198+
uses: actions/upload-artifact@v4
199+
if: always()
200+
with:
201+
name: playwright-report
202+
path: e2e/playwright-report/
203+
retention-days: 30
204+
205+
- name: Upload backend coverage artifact
206+
uses: actions/upload-artifact@v4
207+
if: always()
208+
with:
209+
name: coverage
210+
path: coverage/coverage.txt
211+
retention-days: 30
212+
213+
- name: Upload coverage to Codecov
214+
uses: codecov/codecov-action@v4
215+
if: always()
216+
with:
217+
token: ${{ secrets.CODECOV_TOKEN }}
218+
files: ./coverage/coverage.txt
219+
flags: e2e
220+
name: e2e-tests
221+

.github/workflows/go.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ jobs:
3737
DB_USER: root
3838
DB_PASSWORD: root
3939
DB_DATABASE: nekobox
40+
- name: Upload coverage reports to Codecov
41+
uses: codecov/codecov-action@v5
42+
with:
43+
token: ${{ secrets.CODECOV_TOKEN }}
4044

4145
test-postgres:
4246
name: Test Postgres
@@ -68,6 +72,10 @@ jobs:
6872
DB_USER: postgres
6973
DB_PASSWORD: postgres
7074
DB_DATABASE: nekobox
75+
- name: Upload coverage reports to Codecov
76+
uses: codecov/codecov-action@v5
77+
with:
78+
token: ${{ secrets.CODECOV_TOKEN }}
7179

7280
lint:
7381
name: Lint

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,12 @@ app.ini
2121
.vscode
2222
nekobox
2323
share.yaml
24+
25+
node_modules
26+
27+
# E2E test artifacts
28+
e2e/node_modules
29+
e2e/.auth
30+
e2e/test-results/
31+
e2e/playwright-report/
32+
e2e/.env.local

conf/app.e2e.ini

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
; E2E test configuration.
2+
; Used by: NEKOBOX_CONFIG_PATH=conf/app.e2e.ini
3+
; The Go backend listens on :8080; the Vite dev-server (port 3000)
4+
; proxies /api → http://127.0.0.1:8080.
5+
6+
[app]
7+
production = false
8+
title = NekoBox E2E Test
9+
external_url = http://localhost:3000
10+
11+
[security]
12+
enable_text_censor = false
13+
14+
[server]
15+
port = 8080
16+
salt = e2e-test-salt-value-placeholder
17+
xsrf_key = e2e-test-xsrf-key-placeholder
18+
19+
[database]
20+
type = postgres
21+
host = localhost
22+
port = 5432
23+
user = nekobox
24+
password = nekobox
25+
name = nekobox_e2e
26+
27+
[redis]
28+
addr = localhost:6379
29+
password =
30+
31+
[recaptcha]
32+
; Universal test keys – accepted by Google's verify API for any token.
33+
site_key = 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
34+
server_key = 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
35+
36+
[upload]
37+
default_avatar = https://example.com/default-avatar.png
38+
default_background = https://example.com/default-bg.png
39+
image_endpoint = http://localhost:9000
40+
image_access_id = minioadmin
41+
image_access_secret = minioadmin
42+
image_bucket = nekobox-e2e
43+
image_bucket_cdn_host = localhost:9000
44+
45+
[mail]
46+
account = noreply@nekobox.local
47+
password =
48+
port = 1025
49+
smtp = localhost
50+

0 commit comments

Comments
 (0)