Compare commits

...

48 Commits

Author SHA1 Message Date
zhi
c96d012fef chore: update backend/frontend test submodule pointers to main head 2026-04-05 22:18:01 +00:00
h z
3f09573631 Merge pull request 'HarborForge.Test: update Frontend.Test submodule ref' (#5) from pr/dev-2026-03-29-frontend-test-submodule-20260405 into main
Reviewed-on: #5
2026-04-05 22:12:10 +00:00
zhi
3cd807566a TEST-FE-PR-001: update Frontend.Test submodule ref 2026-04-05 20:49:09 +00:00
zhi
ef8a4ae994 BE-PR-010: update submodule ref for Backend.Test 2026-03-30 12:50:03 +00:00
zhi
4c54503a81 Update HarborForge.Backend.Test submodule ref 2026-03-30 11:46:26 +00:00
zhi
62d339b58c BE-PR-001: Update submodule ref for Backend.Test 2026-03-29 15:35:54 +00:00
zhi
23cad37e03 test: simplify frontend test runner and rely on image default command
- remove --test-real-plugin option
- stop overriding test container CMD
- let Frontend.Test Dockerfile own proxy startup and playwright launch
2026-03-21 10:10:59 +00:00
zhi
779fb7b387 test: update frontend test defaults and propose suite 2026-03-20 11:38:12 +00:00
zhi
48c54c2f32 test: exclude real-plugin frontend test by default
Only run real-plugin.spec.ts when --test-real-plugin is explicitly provided.
2026-03-20 11:26:14 +00:00
zhi
f5294f5290 chore: update backend test submodule pointer 2026-03-20 09:47:51 +00:00
zhi
11d0865fd3 chore: update Frontend.Test with fixed real-plugin test 2026-03-20 05:08:44 +00:00
zhi
14f4fb8d16 chore: update Frontend.Test with real-plugin.spec.ts 2026-03-19 22:25:28 +00:00
zhi
cc2d4aea5c test: add real plugin integration test and --test-real-plugin option
- Add tests/real-plugin.spec.ts for end-to-end plugin testing
- Add --test-real-plugin flag to run-test-frontend.sh
- Test verifies: server registration, API key generation, heartbeat,
  data persistence, invalid key rejection, key revocation
2026-03-19 22:07:54 +00:00
zhi
5a45a72dcf chore: update Backend.Test submodule with comprehensive test suite
134 backend API tests added as independent project
2026-03-19 12:44:29 +00:00
zhi
ba3909ec68 chore: update Frontend.Test to master (includes task type fix) 2026-03-19 12:25:04 +00:00
805dc2fe32 Merge pull request 'chore: run frontend tests with modal-editor updates' (#4) from feat/modal-edit-permissions-20260316 into master
Reviewed-on: #4
2026-03-16 19:44:45 +00:00
zhi
81fe00bfb8 chore: update frontend test submodule for modal editors 2026-03-16 18:13:54 +00:00
zhi
4707f0614c chore: run frontend tests against dev-mode ui 2026-03-16 16:32:26 +00:00
zhi
c76c25fb5b chore: update frontend test submodule 2026-03-16 13:22:28 +00:00
zhi
1bb11ca92b chore: update Frontend.Test submodule (Issue→Task rename) 2026-03-16 07:48:18 +00:00
zhi
4844b63c16 chore: update Frontend.Test submodule (add task.spec.ts) 2026-03-16 07:26:48 +00:00
zhi
8b1edf53f0 chore: update Frontend.Test submodule (test isolation fix) 2026-03-16 06:32:45 +00:00
zhi
3aaffd2e67 chore: update Frontend.Test submodule (fix milestone test flakiness) 2026-03-16 06:17:48 +00:00
zhi
62ca6bd32b test: use local proxy endpoints for e2e 2026-03-15 22:40:17 +00:00
zhi
15859b9f28 test: use localhost wizard/backend urls 2026-03-15 21:57:39 +00:00
zhi
d3c5f6df8c chore: update test submodule pointers 2026-03-15 16:36:24 +00:00
a4620b9604 Merge pull request 'chore: update backend test submodule' (#3) from chore/remove-backend-test-submodule into master
Reviewed-on: #3
2026-03-15 16:33:14 +00:00
b0d6a0bdd7 Merge branch 'master' into chore/remove-backend-test-submodule 2026-03-15 16:33:02 +00:00
zhi
ebdac827c1 chore: update backend test submodule 2026-03-15 16:30:00 +00:00
2424ec33e0 Merge pull request 'test: rebuild backend/test runner and wait for mysql' (#2) from chore/test-runner-rebuild into master
Reviewed-on: #2
2026-03-15 16:23:45 +00:00
zhi
1047110de5 test: rebuild backend/test runner and wait for mysql 2026-03-15 15:56:03 +00:00
95a6354fc3 Merge pull request 'feature/role-permission-system' (#1) from feature/role-permission-system into master
Reviewed-on: #1
2026-03-15 13:50:28 +00:00
524a4a5b46 Update submodule to latest test files 2026-03-15 13:40:50 +00:00
cf4b9f406b fix: run tests with 1 worker to avoid race conditions 2026-03-15 13:36:32 +00:00
3591ef2c84 fix: add --no-cache to ensure frontend rebuilds with correct API base 2026-03-15 12:57:40 +00:00
4c45a57649 fix: always rebuild frontend with correct VITE_API_BASE 2026-03-15 12:48:12 +00:00
Zhi
1524891b2f chore: remove credentials from submodule urls 2026-03-14 13:21:11 +00:00
Zhi
c4bf1f6a12 Use localhost wizard in frontend and add proxy envs 2026-03-14 10:22:57 +00:00
Zhi
9906bf368d Update HarborForge.Frontend.Test submodule to latest 2026-03-14 09:20:14 +00:00
Zhi
149465c919 Use internal service name for test container 2026-03-14 08:51:14 +00:00
Zhi
99ca422c3d Fix CORS and API URLs for container communication 2026-03-14 08:49:12 +00:00
Zhi
b44267aac0 Merge cleanup logic into run-test-frontend
- --expose-port on: keep services running after test
- --expose-port off: auto cleanup (default)
- Removed cleanup-frontend.sh
2026-03-14 08:32:33 +00:00
Zhi
03067ca3a8 Use env vars for ports, add .env.TEST
- WIZARD_PORT, MYSQL_PORT, BACKEND_PORT, FRONTEND_PORT env vars
- .env.TEST with default values (8080, 3306, 8000, 3000)
- Scripts load .env.TEST automatically
- LISTEN_ADDR uses env vars
- Ports bound to 127.0.0.1 for security
2026-03-14 08:20:55 +00:00
Zhi
392e050caa Add separate compose files for port exposure options
- docker-compose-frontend.yml: No port exposure (default)
- docker-compose-frontend-expose.yml: Expose ports to host
- run-test-frontend.sh: Test script with --expose-port {on|off} option
- cleanup-frontend.sh: Cleanup script with --expose-port option
2026-03-14 08:08:50 +00:00
Zhi
3a9850cafb Use docker network for health check 2026-03-14 07:45:23 +00:00
Zhi
71e8cc4e6d Wait for services to be ready before running test 2026-03-14 07:43:19 +00:00
Zhi
074b5df4f5 Add scripts and port mapping env vars 2026-03-14 07:39:17 +00:00
Zhi
f081d53400 Update Frontend.Test to latest 2026-03-14 07:38:53 +00:00
9 changed files with 368 additions and 58 deletions

14
.env.TEST Normal file
View File

@@ -0,0 +1,14 @@
# HarborForge Test Environment Variables
# Default port values
# Wizard service
WIZARD_PORT=8080
# MySQL service
MYSQL_PORT=3306
# Backend service
BACKEND_PORT=8000
# Frontend service
FRONTEND_PORT=3000

4
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "HarborForge.Backend.Test"]
path = HarborForge.Backend.Test
url = https://zhi:rT5Wjw24mV4all38fIoNQfl2@git.hangman-lab.top/zhi/HarborForge.Backend.Test.git
url = https://git.hangman-lab.top/zhi/HarborForge.Backend.Test.git
[submodule "HarborForge.Frontend.Test"]
path = HarborForge.Frontend.Test
url = https://zhi:rT5Wjw24mV4all38fIoNQfl2@git.hangman-lab.top/zhi/HarborForge.Frontend.Test.git
url = https://git.hangman-lab.top/zhi/HarborForge.Frontend.Test.git

17
cleanup.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Cleanup script for HarborForge Test
# Removes containers and networks, but keeps images
set -e
COMPOSE_FILE="docker-compose-frontend.yml"
echo "🧹 Cleaning up HarborForge Test containers..."
# Stop and remove containers, networks (keep images)
docker compose -f "$COMPOSE_FILE" down
# Also remove the wizard config volume
docker volume rm harborforgetest_wizard_config 2>/dev/null || true
echo "✅ Cleanup complete!"

View File

@@ -0,0 +1,116 @@
services:
mysql:
image: mysql:8.0
container_name: harborforge-test-mysql
restart: "no"
tmpfs:
- /var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-harborforge_root}
MYSQL_DATABASE: ${MYSQL_DATABASE:-harborforge}
MYSQL_USER: ${MYSQL_USER:-harborforge}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-harborforge_pass}
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
ports:
- "127.0.0.1:${MYSQL_PORT:-3306}:3306"
networks:
- test-network
wizard:
build:
context: ../AbstractWizard
dockerfile: Dockerfile
image: harborforge-test-wizard:dev
container_name: harborforge-test-wizard
user: 0:0
restart: "no"
volumes:
- wizard_config:/config
environment:
CONFIG_DIR: /config
LISTEN_ADDR: "0.0.0.0:${WIZARD_PORT:-8080}"
MAX_BACKUPS: "5"
CORS_ORIGINS: http://frontend:${FRONTEND_PORT:-3000},http://127.0.0.1:${FRONTEND_PORT:-3000},http://localhost:${FRONTEND_PORT:-3000}
ports:
- "127.0.0.1:${WIZARD_PORT:-8080}:${WIZARD_PORT:-8080}"
networks:
- test-network
backend:
build:
context: ../HarborForge.Backend
dockerfile: Dockerfile
image: harborforge-test-backend:dev
container_name: harborforge-test-backend
restart: "no"
volumes:
- wizard_config:/config:ro
environment:
CONFIG_DIR: /config
CONFIG_FILE: harborforge.json
SECRET_KEY: ${SECRET_KEY:-change_me_in_production}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
DATABASE_URL: mysql+pymysql://harborforge:harborforge_pass@mysql:${MYSQL_PORT:-3306}/harborforge
ports:
- "127.0.0.1:${BACKEND_PORT:-8000}:${BACKEND_PORT:-8000}"
depends_on:
mysql:
condition: service_healthy
networks:
- test-network
frontend:
build:
context: ../HarborForge.Frontend
dockerfile: Dockerfile
args:
VITE_WIZARD_PORT: ${WIZARD_PORT:-8080}
image: harborforge-test-frontend:dev
container_name: harborforge-test-frontend
restart: "no"
environment:
VITE_API_BASE_URL: http://backend:${BACKEND_PORT:-8000}
VITE_WIZARD_PORT: ${WIZARD_PORT:-8080}
FRONTEND_DEV_MODE: ${FRONTEND_DEV_MODE:-1}
NODE_ENV: development
ports:
- "127.0.0.1:${FRONTEND_PORT:-3000}:${FRONTEND_PORT:-3000}"
depends_on:
- wizard
- backend
networks:
- test-network
test:
build:
context: ./HarborForge.Frontend.Test
dockerfile: Dockerfile
image: harborforge-test-runner:dev
container_name: harborforge-test-runner
restart: "no"
environment:
# Use internal service name for test to reach frontend
BASE_URL: http://127.0.0.1:${FRONTEND_PORT:-3000}
FRONTEND_URL: http://127.0.0.1:${FRONTEND_PORT:-3000}
WEB_SERVER_URL: http://127.0.0.1:${FRONTEND_PORT:-3000}
WIZARD_URL: http://127.0.0.1:${WIZARD_PORT:-8080}/wizard
WIZARD_API_URL: http://127.0.0.1:${WIZARD_PORT:-8080}
WIZARD_HOST: wizard
WIZARD_PORT: ${WIZARD_PORT:-8080}
BACKEND_URL: http://127.0.0.1:${BACKEND_PORT:-8000}
BACKEND_HOST: backend
FRONTEND_HOST: frontend
CHROME_DEBUGGING_PORT: 9222
networks:
- test-network
volumes:
wizard_config:
networks:
test-network:
driver: bridge

View File

@@ -2,7 +2,9 @@ services:
mysql:
image: mysql:8.0
container_name: harborforge-test-mysql
restart: unless-stopped
restart: "no"
tmpfs:
- /var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-harborforge_root}
MYSQL_DATABASE: ${MYSQL_DATABASE:-harborforge}
@@ -13,11 +15,6 @@ services:
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
networks:
- test-network
@@ -28,21 +25,17 @@ services:
image: harborforge-test-wizard:dev
container_name: harborforge-test-wizard
user: 0:0
restart: unless-stopped
restart: "no"
volumes:
- wizard_config:/config
environment:
CONFIG_DIR: /config
LISTEN_ADDR: "0.0.0.0:8080"
LISTEN_ADDR: "0.0.0.0:${WIZARD_PORT:-8080}"
MAX_BACKUPS: "5"
CORS_ORIGINS: http://frontend:3000
# Internal network only
CORS_ORIGINS: http://frontend:${FRONTEND_PORT:-3000}
ports:
- "${WIZARD_PORT:-18080}:8080"
deploy:
resources:
limits:
cpus: '0.1'
memory: 64M
- "127.0.0.1:${WIZARD_PORT:-8080}:${WIZARD_PORT:-8080}"
networks:
- test-network
@@ -52,29 +45,18 @@ services:
dockerfile: Dockerfile
image: harborforge-test-backend:dev
container_name: harborforge-test-backend
restart: unless-stopped
restart: "no"
volumes:
- wizard_config:/config:ro
environment:
CONFIG_DIR: /config
CONFIG_FILE: harborforge.json
SECRET_KEY: ${SECRET_KEY:-change_me_in_production}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
DATABASE_URL: mysql+pymysql://harborforge:harborforge_pass@mysql:3306/harborforge
volumes:
- wizard_config:/config:ro
DATABASE_URL: mysql+pymysql://harborforge:harborforge_pass@mysql:${MYSQL_PORT:-3306}/harborforge
depends_on:
mysql:
condition: service_healthy
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
- test-network
@@ -83,25 +65,16 @@ services:
context: ../HarborForge.Frontend
dockerfile: Dockerfile
args:
VITE_WIZARD_PORT: 8080
VITE_WIZARD_PORT: ${WIZARD_PORT:-8080}
image: harborforge-test-frontend:dev
container_name: harborforge-test-frontend
restart: unless-stopped
restart: "no"
environment:
VITE_API_BASE_URL: http://backend:8000
depends_on:
- wizard
- backend
deploy:
resources:
limits:
cpus: '0.25'
memory: 128M
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
# Use internal service name
VITE_API_BASE_URL: http://backend:${BACKEND_PORT:-8000}
VITE_WIZARD_PORT: ${WIZARD_PORT:-8080}
FRONTEND_DEV_MODE: ${FRONTEND_DEV_MODE:-1}
NODE_ENV: development
networks:
- test-network
@@ -113,20 +86,18 @@ services:
container_name: harborforge-test-runner
restart: "no"
environment:
BASE_URL: http://frontend:3000
WEB_SERVER_URL: http://frontend:3000
BASE_URL: http://frontend:${FRONTEND_PORT:-3000}
WEB_SERVER_URL: http://frontend:${FRONTEND_PORT:-3000}
WIZARD_URL: http://wizard:${WIZARD_PORT:-8080}/wizard
WIZARD_API_URL: http://wizard:${WIZARD_PORT:-8080}
WIZARD_HOST: wizard
WIZARD_PORT: ${WIZARD_PORT:-8080}
CHROME_DEBUGGING_PORT: 9222
depends_on:
frontend:
condition: service_healthy
backend:
condition: service_healthy
networks:
- test-network
volumes:
wizard_config:
driver: local
networks:
test-network:

143
run-test-frontend.sh Executable file
View File

@@ -0,0 +1,143 @@
#!/bin/bash
# Run frontend test with optional port exposure
# Usage: ./run-test-frontend.sh [--expose-port {on|off}]
# Default:
# --expose-port off: Auto cleanup after test
set -e
EXPOSE_PORT="off"
COMPOSE_FILE="docker-compose-frontend.yml"
# Load environment variables from .env.TEST if exists
if [ -f ".env.TEST" ]; then
echo "📋 Loading .env.TEST..."
set -a
source .env.TEST
set +a
fi
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--expose-port)
EXPOSE_PORT="$2"
shift 2
;;
--expose-port=*)
EXPOSE_PORT="${1#*=}"
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [--expose-port {on|off}]"
exit 1
;;
esac
done
# Validate expose-port value
if [[ "$EXPOSE_PORT" != "on" && "$EXPOSE_PORT" != "off" ]]; then
echo "Error: --expose-port must be 'on' or 'off'"
exit 1
fi
# Select compose file based on expose-port
if [[ "$EXPOSE_PORT" == "on" ]]; then
COMPOSE_FILE="docker-compose-frontend-expose.yml"
echo "🔌 Port exposure: ON (services will keep running)"
else
echo "🔌 Port exposure: OFF (auto cleanup after test)"
fi
echo "📦 Using compose file: $COMPOSE_FILE"
run_quiet() {
local label="$1"
shift
local log_file
log_file=$(mktemp)
if "$@" >"$log_file" 2>&1; then
rm -f "$log_file"
return 0
fi
echo "${label} failed"
echo "--- ${label} log ---"
tail -n 200 "$log_file"
rm -f "$log_file"
return 1
}
# Clean any previous containers first
echo "🧹 Cleaning up previous containers..."
docker compose -f "$COMPOSE_FILE" down -v >/dev/null 2>&1 || true
# Build frontend with correct API base URL (force no cache, remove image first)
echo "🔨 Building frontend..."
docker rmi harborforge-test-frontend:dev >/dev/null 2>&1 || true
run_quiet "frontend build" docker compose -f "$COMPOSE_FILE" build --no-cache --build-arg VITE_API_BASE=http://backend:8000 frontend
# Build backend (force no cache, remove image first)
echo "🔨 Building backend..."
docker rmi harborforge-test-backend:dev >/dev/null 2>&1 || true
run_quiet "backend build" docker compose -f "$COMPOSE_FILE" build --no-cache backend
# Build test runner (force no cache, remove image first)
echo "🔨 Building test runner..."
docker rmi harborforge-test-runner:dev >/dev/null 2>&1 || true
run_quiet "test runner build" docker compose -f "$COMPOSE_FILE" build --no-cache test
# Start services
echo "📦 Starting services..."
run_quiet "service startup" docker compose -f "$COMPOSE_FILE" up -d
# Wait for frontend to be ready
echo "⏳ Waiting for services..."
MAX_RETRIES=30
RETRY_COUNT=0
until docker run --rm --network harborforgetest_test-network curlimages/curl -s -o /dev/null -w "%{http_code}" http://frontend:3000/ 2>/dev/null | grep -q "200" || [ $RETRY_COUNT -eq $MAX_RETRIES ]; do
echo " Waiting for frontend... ($RETRY_COUNT/$MAX_RETRIES)"
sleep 2
RETRY_COUNT=$((RETRY_COUNT+1))
done
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "❌ Frontend failed to start"
docker compose -f "$COMPOSE_FILE" logs
docker compose -f "$COMPOSE_FILE" down -v
exit 1
fi
echo "✅ Services ready!"
# Run test using the image default CMD so proxy startup stays inside Frontend.Test Dockerfile
echo "🧪 Running test..."
docker compose -f "$COMPOSE_FILE" run --rm -e WORKERS=1 test
TEST_EXIT_CODE=$?
# Cleanup decision based on expose-port
if [[ "$EXPOSE_PORT" == "on" ]]; then
echo ""
echo "🔌 Port exposure is ON - keeping services running!"
echo " Use './run-test-frontend.sh --expose-port on' to cleanup"
echo " Or manually: docker compose -f $COMPOSE_FILE down -v"
echo ""
if [ $TEST_EXIT_CODE -eq 0 ]; then
echo "✅ Test passed!"
else
echo "❌ Test failed with exit code: $TEST_EXIT_CODE"
fi
else
echo ""
echo "🧹 Cleaning up containers and volumes..."
docker compose -f "$COMPOSE_FILE" down -v
if [ $TEST_EXIT_CODE -eq 0 ]; then
echo "✅ Test passed!"
else
echo "❌ Test failed with exit code: $TEST_EXIT_CODE"
fi
fi
exit $TEST_EXIT_CODE

49
run-test.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
# Run test and cleanup afterwards
set -e
COMPOSE_FILE="docker-compose-frontend.yml"
echo "🚀 Running HarborForge Test..."
# Clean any previous containers first
docker compose -f "$COMPOSE_FILE" down 2>/dev/null || true
# Start services
echo "📦 Starting services..."
docker compose -f "$COMPOSE_FILE" up -d
# Wait for frontend to be ready (run curl inside docker network)
echo "⏳ Waiting for services..."
MAX_RETRIES=30
RETRY_COUNT=0
until docker run --rm --network harborforgetest_test-network curlimages/curl -s -o /dev/null -w "%{http_code}" http://frontend:3000/ 2>/dev/null | grep -q "200" || [ $RETRY_COUNT -eq $MAX_RETRIES ]; do
echo " Waiting for frontend... ($RETRY_COUNT/$MAX_RETRIES)"
sleep 2
RETRY_COUNT=$((RETRY_COUNT+1))
done
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "❌ Frontend failed to start"
docker compose -f "$COMPOSE_FILE" logs
docker compose -f "$COMPOSE_FILE" down -v
exit 1
fi
echo "✅ Services ready!"
# Run test
docker compose -f "$COMPOSE_FILE" run --rm test
TEST_EXIT_CODE=$?
echo ""
echo "🧹 Cleaning up containers and volumes..."
docker compose -f "$COMPOSE_FILE" down -v
if [ $TEST_EXIT_CODE -eq 0 ]; then
echo "✅ Test passed!"
else
echo "❌ Test failed with exit code: $TEST_EXIT_CODE"
fi
exit $TEST_EXIT_CODE