From 3e08a09d87a78946c0b678f90674f2282c9aa64b Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Fri, 28 Mar 2025 09:33:59 +0100 Subject: [PATCH] Add frontend test environment with real backend integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces a proper integration test environment for the frontend: - Creates a test environment option in the frontend installer - Uses the real backend in Docker containers - Binds frontend to 127.0.0.1 for local testing only - Adds automatic verification testing of backend-frontend communication - Provides scripts to easily start and stop the test environment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- packages/reservation-platform/.gitignore | 2 + .../reservation-platform/docker/test-env.yml | 45 ++ .../docker/test-integration.sh | 164 +++++ .../reservation-platform/install-frontend.sh | 657 +++++++++++++++++- packages/reservation-platform/package.json | 8 + 5 files changed, 873 insertions(+), 3 deletions(-) create mode 100644 packages/reservation-platform/docker/test-env.yml create mode 100755 packages/reservation-platform/docker/test-integration.sh diff --git a/packages/reservation-platform/.gitignore b/packages/reservation-platform/.gitignore index 7002099..bb1d3cb 100755 --- a/packages/reservation-platform/.gitignore +++ b/packages/reservation-platform/.gitignore @@ -15,6 +15,8 @@ db/ # testing /coverage +/cypress/videos +/cypress/screenshots # next.js /.next/ diff --git a/packages/reservation-platform/docker/test-env.yml b/packages/reservation-platform/docker/test-env.yml new file mode 100644 index 0000000..ffad4a4 --- /dev/null +++ b/packages/reservation-platform/docker/test-env.yml @@ -0,0 +1,45 @@ +version: '3.8' + +services: + # Backend for testing + backend: + build: + context: ../../backend + dockerfile: Dockerfile + container_name: myp-backend-test + ports: + - "5000:5000" + environment: + - SECRET_KEY=testsecretkey123456789 + - DATABASE_URL=sqlite:///myp.db + - FLASK_ENV=development + - TESTING=true + volumes: + - backend-test-data:/app/instance + networks: + - test-network + + # Frontend for testing - bound to loopback address + frontend-test: + build: + context: .. + dockerfile: Dockerfile + container_name: myp-frontend-test + environment: + - NODE_ENV=development + - AUTH_TRUST_HOST=true + - AUTH_SECRET=test-secret-key-for-testing-only-do-not-use-in-production + - NEXT_PUBLIC_BACKEND_URL=http://backend:5000 + ports: + - "127.0.0.1:3000:3000" + depends_on: + - backend + networks: + - test-network + +networks: + test-network: + driver: bridge + +volumes: + backend-test-data: \ No newline at end of file diff --git a/packages/reservation-platform/docker/test-integration.sh b/packages/reservation-platform/docker/test-integration.sh new file mode 100755 index 0000000..6da4a92 --- /dev/null +++ b/packages/reservation-platform/docker/test-integration.sh @@ -0,0 +1,164 @@ +#!/bin/bash + +# Test integration script - validates if the frontend and backend work together +# Specifically designed to test if the production environment setup will work + +# Get the directory containing this script +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PARENT_DIR="$(dirname "$SCRIPT_DIR")" +TEST_LOG="$SCRIPT_DIR/test-integration.log" + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Create or clear log file +> "$TEST_LOG" + +echo -e "${YELLOW}Starting MYP integration test environment...${NC}" | tee -a "$TEST_LOG" +echo "Test directory: $SCRIPT_DIR" | tee -a "$TEST_LOG" +echo "Parent directory: $PARENT_DIR" | tee -a "$TEST_LOG" +echo "Log file: $TEST_LOG" | tee -a "$TEST_LOG" + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Docker is not installed or not in PATH${NC}" | tee -a "$TEST_LOG" + exit 1 +fi + +# Function to run docker compose (handles both docker-compose and docker compose syntax) +run_docker_compose() { + if command -v docker-compose &> /dev/null; then + docker-compose "$@" + else + docker compose "$@" + fi +} + +# Stop any existing test environment (cleanup) +echo -e "${YELLOW}Cleaning up any existing test environment...${NC}" | tee -a "$TEST_LOG" +run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + +# Start the test environment +echo -e "${YELLOW}Starting test environment with docker-compose...${NC}" | tee -a "$TEST_LOG" +run_docker_compose -f "$SCRIPT_DIR/test-env.yml" up -d >> "$TEST_LOG" 2>&1 + +if [ $? -ne 0 ]; then + echo -e "${RED}Failed to start test environment.${NC}" | tee -a "$TEST_LOG" + echo "Check the log file for details: $TEST_LOG" | tee -a "$TEST_LOG" + exit 1 +fi + +# Wait for backend to be ready +echo -e "${YELLOW}Waiting for backend to be ready...${NC}" | tee -a "$TEST_LOG" +max_attempts=30 +attempt=1 +backend_ready=false + +while [ $attempt -le $max_attempts ] && [ "$backend_ready" = "false" ]; do + echo "Checking backend readiness (attempt $attempt/$max_attempts)..." | tee -a "$TEST_LOG" + + if curl -s http://localhost:5000/api/health &> /dev/null; then + backend_ready=true + echo -e "${GREEN}Backend is ready!${NC}" | tee -a "$TEST_LOG" + else + echo "Backend not ready yet, waiting..." | tee -a "$TEST_LOG" + sleep 2 + attempt=$((attempt+1)) + fi +done + +if [ "$backend_ready" = "false" ]; then + echo -e "${RED}Backend failed to start properly after $max_attempts attempts${NC}" | tee -a "$TEST_LOG" + echo "Logs from backend container:" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" logs backend >> "$TEST_LOG" 2>&1 + + # Cleanup + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + exit 1 +fi + +# Wait for frontend to be ready +echo -e "${YELLOW}Waiting for frontend to be ready...${NC}" | tee -a "$TEST_LOG" +max_attempts=30 +attempt=1 +frontend_ready=false + +while [ $attempt -le $max_attempts ] && [ "$frontend_ready" = "false" ]; do + echo "Checking frontend readiness (attempt $attempt/$max_attempts)..." | tee -a "$TEST_LOG" + + if curl -s http://127.0.0.1:3000 &> /dev/null; then + frontend_ready=true + echo -e "${GREEN}Frontend is ready!${NC}" | tee -a "$TEST_LOG" + else + echo "Frontend not ready yet, waiting..." | tee -a "$TEST_LOG" + sleep 2 + attempt=$((attempt+1)) + fi +done + +if [ "$frontend_ready" = "false" ]; then + echo -e "${RED}Frontend failed to start properly after $max_attempts attempts${NC}" | tee -a "$TEST_LOG" + echo "Logs from frontend container:" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" logs frontend-test >> "$TEST_LOG" 2>&1 + + # Cleanup + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + exit 1 +fi + +# Perform basic integration tests +echo -e "${YELLOW}Performing basic integration tests...${NC}" | tee -a "$TEST_LOG" + +# Test 1: Frontend can fetch API data (printers endpoint) +echo "Test 1: Frontend can fetch data from backend API..." | tee -a "$TEST_LOG" +frontend_container_id=$(docker ps -qf "name=myp-frontend-test") +if [ -z "$frontend_container_id" ]; then + echo -e "${RED}Failed to find frontend container${NC}" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + exit 1 +fi + +# Run a simple test inside the frontend container to check API connectivity +api_test_result=$(docker exec $frontend_container_id curl -s http://backend:5000/api/health) +if [[ "$api_test_result" == *"healthy"* ]]; then + echo -e "${GREEN}Test 1 PASSED: Frontend can connect to backend API${NC}" | tee -a "$TEST_LOG" +else + echo -e "${RED}Test 1 FAILED: Frontend cannot connect to backend API${NC}" | tee -a "$TEST_LOG" + echo "API response: $api_test_result" | tee -a "$TEST_LOG" + # Don't exit, continue with other tests +fi + +# Test 2: Frontend serves HTML content +echo "Test 2: Frontend serves valid HTML content..." | tee -a "$TEST_LOG" +frontend_html=$(curl -s http://127.0.0.1:3000) +if [[ "$frontend_html" == *""* ]]; then + echo -e "${GREEN}Test 2 PASSED: Frontend serves valid HTML${NC}" | tee -a "$TEST_LOG" +else + echo -e "${RED}Test 2 FAILED: Frontend does not serve valid HTML${NC}" | tee -a "$TEST_LOG" + # Don't exit, continue with other tests +fi + +# All tests completed +echo -e "${GREEN}Integration tests completed${NC}" | tee -a "$TEST_LOG" + +# Ask if the environment should be kept running or shutdown +echo -e "${YELLOW}Test environment is running at:${NC}" | tee -a "$TEST_LOG" +echo "Frontend: http://127.0.0.1:3000" | tee -a "$TEST_LOG" +echo "Backend: http://localhost:5000" | tee -a "$TEST_LOG" +echo "" | tee -a "$TEST_LOG" + +read -p "Do you want to keep the test environment running? (y/n): " keep_running + +if [[ "$keep_running" != "y" && "$keep_running" != "Y" ]]; then + echo -e "${YELLOW}Shutting down test environment...${NC}" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + echo -e "${GREEN}Test environment has been shut down${NC}" | tee -a "$TEST_LOG" +else + echo -e "${GREEN}Test environment is still running${NC}" | tee -a "$TEST_LOG" + echo "To stop it later, run: docker-compose -f $SCRIPT_DIR/test-env.yml down" | tee -a "$TEST_LOG" +fi + +echo -e "${GREEN}Integration testing completed. See log for details: $TEST_LOG${NC}" \ No newline at end of file diff --git a/packages/reservation-platform/install-frontend.sh b/packages/reservation-platform/install-frontend.sh index 8eb3e6e..6bfcd46 100755 --- a/packages/reservation-platform/install-frontend.sh +++ b/packages/reservation-platform/install-frontend.sh @@ -89,7 +89,8 @@ apt upgrade -y >> "$LOG_FILE" 2>&1 log "Installing essential system packages and network tools..." apt install -y curl git wget htop net-tools iptables iputils-ping traceroute nmap tcpdump nftables \ netcat-openbsd dnsutils whois vim nano rsync zip unzip xz-utils sqlite3 \ - apt-transport-https ca-certificates gnupg lsb-release >> "$LOG_FILE" 2>&1 + apt-transport-https ca-certificates gnupg lsb-release bash-completion \ + make build-essential libssl-dev zlib1g-dev >> "$LOG_FILE" 2>&1 # Install Docker using the official Docker repository log "Installing Docker from official repository..." @@ -258,17 +259,296 @@ mkdir -p /srv/MYP-DB if [ -n "$1" ] && [ "$1" == "--auto-production" ]; then log "Running in automatic production mode (non-interactive)..." production_mode="y" + test_environment="n" elif [ -n "$1" ] && [ "$1" == "--auto-development" ]; then log "Running in automatic development mode (non-interactive)..." production_mode="n" + test_environment="n" +elif [ -n "$1" ] && [ "$1" == "--auto-test" ]; then + log "Running in automatic test environment mode (non-interactive)..." + production_mode="n" + test_environment="y" else # Interactive mode log "Running in interactive mode..." # Check if we need to run in development or production mode - read -p "Do you want to set up the frontend in production mode? (y/n): " production_mode + echo "Choose installation type:" + echo "1) Production mode (Docker container)" + echo "2) Development mode (local dev server)" + echo "3) Test environment (integrates with real backend)" + read -p "Enter your choice (1-3): " install_choice + + case $install_choice in + 1) + production_mode="y" + test_environment="n" + ;; + 2) + production_mode="n" + test_environment="n" + ;; + 3) + production_mode="n" + test_environment="y" + ;; + *) + log "Invalid choice. Defaulting to development mode." + production_mode="n" + test_environment="n" + ;; + esac fi -if [ "$production_mode" = "y" ] || [ "$production_mode" = "Y" ]; then +if [ "$test_environment" = "y" ] || [ "$test_environment" = "Y" ]; then + # Test environment mode - using Docker for integration testing + log "Setting up test environment for integration testing..." + + # Ensure test directory exists + mkdir -p "$SCRIPT_DIR/docker" + + # Create test environment compose file if it doesn't exist + if [ ! -f "$SCRIPT_DIR/docker/test-env.yml" ]; then + log "Creating test environment docker-compose file..." + cat > "$SCRIPT_DIR/docker/test-env.yml" << EOF +version: '3.8' + +services: + # Backend for testing + backend: + build: + context: ../../backend + dockerfile: Dockerfile + container_name: myp-backend-test + ports: + - "5000:5000" + environment: + - SECRET_KEY=testsecretkey123456789 + - DATABASE_URL=sqlite:///myp.db + - FLASK_ENV=development + - TESTING=true + volumes: + - backend-test-data:/app/instance + networks: + - test-network + + # Frontend for testing - bound to loopback address + frontend-test: + build: + context: .. + dockerfile: Dockerfile + container_name: myp-frontend-test + environment: + - NODE_ENV=development + - AUTH_TRUST_HOST=true + - AUTH_SECRET=test-secret-key-for-testing-only-do-not-use-in-production + - NEXT_PUBLIC_BACKEND_URL=http://backend:5000 + ports: + - "127.0.0.1:3000:3000" + depends_on: + - backend + networks: + - test-network + +networks: + test-network: + driver: bridge + +volumes: + backend-test-data: +EOF + log "Test environment docker-compose file created" + fi + + # Create test integration script if it doesn't exist + if [ ! -f "$SCRIPT_DIR/docker/test-integration.sh" ]; then + log "Creating test integration script..." + cat > "$SCRIPT_DIR/docker/test-integration.sh" << 'EOF' +#!/bin/bash + +# Test integration script - validates if the frontend and backend work together +# Specifically designed to test if the production environment setup will work + +# Get the directory containing this script +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PARENT_DIR="$(dirname "$SCRIPT_DIR")" +TEST_LOG="$SCRIPT_DIR/test-integration.log" + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Create or clear log file +> "$TEST_LOG" + +echo -e "${YELLOW}Starting MYP integration test environment...${NC}" | tee -a "$TEST_LOG" +echo "Test directory: $SCRIPT_DIR" | tee -a "$TEST_LOG" +echo "Parent directory: $PARENT_DIR" | tee -a "$TEST_LOG" +echo "Log file: $TEST_LOG" | tee -a "$TEST_LOG" + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Docker is not installed or not in PATH${NC}" | tee -a "$TEST_LOG" + exit 1 +fi + +# Function to run docker compose (handles both docker-compose and docker compose syntax) +run_docker_compose() { + if command -v docker-compose &> /dev/null; then + docker-compose "$@" + else + docker compose "$@" + fi +} + +# Stop any existing test environment (cleanup) +echo -e "${YELLOW}Cleaning up any existing test environment...${NC}" | tee -a "$TEST_LOG" +run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + +# Start the test environment +echo -e "${YELLOW}Starting test environment with docker-compose...${NC}" | tee -a "$TEST_LOG" +run_docker_compose -f "$SCRIPT_DIR/test-env.yml" up -d >> "$TEST_LOG" 2>&1 + +if [ $? -ne 0 ]; then + echo -e "${RED}Failed to start test environment.${NC}" | tee -a "$TEST_LOG" + echo "Check the log file for details: $TEST_LOG" | tee -a "$TEST_LOG" + exit 1 +fi + +# Wait for backend to be ready +echo -e "${YELLOW}Waiting for backend to be ready...${NC}" | tee -a "$TEST_LOG" +max_attempts=30 +attempt=1 +backend_ready=false + +while [ $attempt -le $max_attempts ] && [ "$backend_ready" = "false" ]; do + echo "Checking backend readiness (attempt $attempt/$max_attempts)..." | tee -a "$TEST_LOG" + + if curl -s http://localhost:5000/api/health &> /dev/null; then + backend_ready=true + echo -e "${GREEN}Backend is ready!${NC}" | tee -a "$TEST_LOG" + else + echo "Backend not ready yet, waiting..." | tee -a "$TEST_LOG" + sleep 2 + attempt=$((attempt+1)) + fi +done + +if [ "$backend_ready" = "false" ]; then + echo -e "${RED}Backend failed to start properly after $max_attempts attempts${NC}" | tee -a "$TEST_LOG" + echo "Logs from backend container:" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" logs backend >> "$TEST_LOG" 2>&1 + + # Cleanup + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + exit 1 +fi + +# Wait for frontend to be ready +echo -e "${YELLOW}Waiting for frontend to be ready...${NC}" | tee -a "$TEST_LOG" +max_attempts=30 +attempt=1 +frontend_ready=false + +while [ $attempt -le $max_attempts ] && [ "$frontend_ready" = "false" ]; do + echo "Checking frontend readiness (attempt $attempt/$max_attempts)..." | tee -a "$TEST_LOG" + + if curl -s http://127.0.0.1:3000 &> /dev/null; then + frontend_ready=true + echo -e "${GREEN}Frontend is ready!${NC}" | tee -a "$TEST_LOG" + else + echo "Frontend not ready yet, waiting..." | tee -a "$TEST_LOG" + sleep 2 + attempt=$((attempt+1)) + fi +done + +if [ "$frontend_ready" = "false" ]; then + echo -e "${RED}Frontend failed to start properly after $max_attempts attempts${NC}" | tee -a "$TEST_LOG" + echo "Logs from frontend container:" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" logs frontend-test >> "$TEST_LOG" 2>&1 + + # Cleanup + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + exit 1 +fi + +# Perform basic integration tests +echo -e "${YELLOW}Performing basic integration tests...${NC}" | tee -a "$TEST_LOG" + +# Test 1: Frontend can fetch API data (printers endpoint) +echo "Test 1: Frontend can fetch data from backend API..." | tee -a "$TEST_LOG" +frontend_container_id=$(docker ps -qf "name=myp-frontend-test") +if [ -z "$frontend_container_id" ]; then + echo -e "${RED}Failed to find frontend container${NC}" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + exit 1 +fi + +# Run a simple test inside the frontend container to check API connectivity +api_test_result=$(docker exec $frontend_container_id curl -s http://backend:5000/api/health) +if [[ "$api_test_result" == *"healthy"* ]]; then + echo -e "${GREEN}Test 1 PASSED: Frontend can connect to backend API${NC}" | tee -a "$TEST_LOG" +else + echo -e "${RED}Test 1 FAILED: Frontend cannot connect to backend API${NC}" | tee -a "$TEST_LOG" + echo "API response: $api_test_result" | tee -a "$TEST_LOG" + # Don't exit, continue with other tests +fi + +# Test 2: Frontend serves HTML content +echo "Test 2: Frontend serves valid HTML content..." | tee -a "$TEST_LOG" +frontend_html=$(curl -s http://127.0.0.1:3000) +if [[ "$frontend_html" == *""* ]]; then + echo -e "${GREEN}Test 2 PASSED: Frontend serves valid HTML${NC}" | tee -a "$TEST_LOG" +else + echo -e "${RED}Test 2 FAILED: Frontend does not serve valid HTML${NC}" | tee -a "$TEST_LOG" + # Don't exit, continue with other tests +fi + +# All tests completed +echo -e "${GREEN}Integration tests completed${NC}" | tee -a "$TEST_LOG" + +# Ask if the environment should be kept running or shutdown +echo -e "${YELLOW}Test environment is running at:${NC}" | tee -a "$TEST_LOG" +echo "Frontend: http://127.0.0.1:3000" | tee -a "$TEST_LOG" +echo "Backend: http://localhost:5000" | tee -a "$TEST_LOG" +echo "" | tee -a "$TEST_LOG" + +read -p "Do you want to keep the test environment running? (y/n): " keep_running + +if [[ "$keep_running" != "y" && "$keep_running" != "Y" ]]; then + echo -e "${YELLOW}Shutting down test environment...${NC}" | tee -a "$TEST_LOG" + run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1 + echo -e "${GREEN}Test environment has been shut down${NC}" | tee -a "$TEST_LOG" +else + echo -e "${GREEN}Test environment is still running${NC}" | tee -a "$TEST_LOG" + echo "To stop it later, run: docker-compose -f $SCRIPT_DIR/test-env.yml down" | tee -a "$TEST_LOG" +fi + +echo -e "${GREEN}Integration testing completed. See log for details: $TEST_LOG${NC}" +EOF + chmod +x "$SCRIPT_DIR/docker/test-integration.sh" + log "Test integration script created and made executable" + fi + + # Run the integration test + log "Running integration test to verify the environment..." + "$SCRIPT_DIR/docker/test-integration.sh" + + # Add entries to package.json for running tests + if ! grep -q "test:integration" "$SCRIPT_DIR/package.json"; then + log "Adding test integration commands to package.json..." + # This approach requires jq, which might not be installed. Using a temporary approach. + # Would be better to use jq for proper JSON manipulation + sed -i 's/"scripts": {/"scripts": {\n "test:integration": "bash docker\/test-integration.sh",/g' "$SCRIPT_DIR/package.json" + fi + + log "Test environment setup complete!" + log "To run integration tests again: cd $SCRIPT_DIR && pnpm test:integration" + log "Or directly: $SCRIPT_DIR/docker/test-integration.sh" + +elif [ "$production_mode" = "y" ] || [ "$production_mode" = "Y" ]; then # Production mode - using Docker log "Setting up in production mode using Docker..." @@ -324,6 +604,254 @@ EOF log "docker-compose.yml created with backend network configuration" fi + # Create Docker Compose for testing environment if it doesn't exist + if [ ! -d "$SCRIPT_DIR/cypress" ]; then + log "Creating Cypress directory for testing..." + mkdir -p "$SCRIPT_DIR/cypress" + fi + + if [ ! -f "$SCRIPT_DIR/cypress/docker-compose.test.yml" ]; then + log "Creating docker-compose.test.yml for testing environment..." + cat > "$SCRIPT_DIR/cypress/docker-compose.test.yml" << EOF +version: '3.8' + +services: + # Backend service + backend: + build: + context: ../../../backend + dockerfile: Dockerfile + container_name: myp-backend-test + ports: + - "5000:5000" + environment: + - SECRET_KEY=testsecretkey123456789 + - DATABASE_URL=sqlite:///myp.db + - FLASK_ENV=development + - TESTING=true + volumes: + - backend-test-data:/app/instance + restart: unless-stopped + networks: + - test-network + + # Optional: Frontend test service if needed + frontend-test: + image: cypress/included:13.6.1 + container_name: myp-frontend-test + depends_on: + - backend + environment: + - CYPRESS_baseUrl=http://host.docker.internal:3000 + - CYPRESS_backendUrl=http://backend:5000 + volumes: + - ..:/app + - ./cypress.config.ts:/app/cypress.config.ts + working_dir: /app + command: npx cypress run + networks: + - test-network + +networks: + test-network: + driver: bridge + +volumes: + backend-test-data: +EOF + log "Test environment docker-compose.yml created" + fi + + if [ ! -f "$SCRIPT_DIR/cypress/start-test-environment.sh" ]; then + log "Creating test environment startup script..." + cat > "$SCRIPT_DIR/cypress/start-test-environment.sh" << 'EOF' +#!/bin/bash + +# Script to start a test environment with backend and optional test runner + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PARENT_DIR="$(dirname "$SCRIPT_DIR")" +BACKEND_DIR="$(dirname "$(dirname "$PARENT_DIR")")/backend" + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +echo -e "${GREEN}Starting MYP test environment...${NC}" +echo "Script directory: $SCRIPT_DIR" +echo "Frontend directory: $PARENT_DIR" +echo "Backend directory: $BACKEND_DIR" + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Docker is not installed or not in PATH${NC}" + exit 1 +fi + +# Check if docker-compose is available +if ! command -v docker-compose &> /dev/null && ! command -v docker compose &> /dev/null; then + echo -e "${RED}Error: Neither docker-compose nor docker compose is available${NC}" + exit 1 +fi + +# Function to run docker compose (handles both docker-compose and docker compose syntax) +run_docker_compose() { + if command -v docker-compose &> /dev/null; then + docker-compose "$@" + else + docker compose "$@" + fi +} + +# Check if backend Docker image exists +echo -e "${YELLOW}Checking for backend Docker image...${NC}" +cd "$SCRIPT_DIR" + +# Start the backend container +echo -e "${GREEN}Starting backend container...${NC}" +run_docker_compose -f docker-compose.test.yml up -d backend + +# Wait for backend to be ready +echo -e "${YELLOW}Waiting for backend to be ready...${NC}" +max_attempts=30 +attempt=1 +backend_ready=false + +while [ $attempt -le $max_attempts ] && [ "$backend_ready" = "false" ]; do + echo "Checking backend readiness (attempt $attempt/$max_attempts)..." + + if curl -s http://localhost:5000/api/health 2>&1 | grep -q "healthy"; then + backend_ready=true + echo -e "${GREEN}Backend is ready!${NC}" + else + echo "Backend not ready yet, waiting..." + sleep 2 + attempt=$((attempt+1)) + fi +done + +if [ "$backend_ready" = "false" ]; then + echo -e "${RED}Backend failed to start properly after $max_attempts attempts${NC}" + echo "Logs from backend container:" + run_docker_compose -f docker-compose.test.yml logs backend + exit 1 +fi + +# Start frontend development server if it's not already running +if ! curl -s http://localhost:3000 > /dev/null; then + echo -e "${YELLOW}Starting frontend development server...${NC}" + cd "$PARENT_DIR" + + # Run in background + echo "Starting Next.js development server in the background..." + nohup pnpm dev > "$SCRIPT_DIR/frontend.log" 2>&1 & + + # Store the PID for later cleanup + FRONTEND_PID=$! + echo $FRONTEND_PID > "$SCRIPT_DIR/frontend.pid" + + echo -e "${GREEN}Frontend development server started with PID $FRONTEND_PID${NC}" + echo "Frontend logs available at: $SCRIPT_DIR/frontend.log" + + # Wait for frontend to be ready + echo -e "${YELLOW}Waiting for frontend to be ready...${NC}" + max_attempts=30 + attempt=1 + frontend_ready=false + + while [ $attempt -le $max_attempts ] && [ "$frontend_ready" = "false" ]; do + echo "Checking frontend readiness (attempt $attempt/$max_attempts)..." + + if curl -s http://localhost:3000 > /dev/null; then + frontend_ready=true + echo -e "${GREEN}Frontend is ready!${NC}" + else + echo "Frontend not ready yet, waiting..." + sleep 2 + attempt=$((attempt+1)) + fi + done + + if [ "$frontend_ready" = "false" ]; then + echo -e "${RED}Frontend failed to start properly${NC}" + exit 1 + fi +else + echo -e "${GREEN}Frontend already running at http://localhost:3000${NC}" +fi + +echo -e "${GREEN}Test environment is ready!${NC}" +echo "Backend is available at: http://localhost:5000" +echo "Frontend is available at: http://localhost:3000" +echo "" +echo "To run Cypress tests:" +echo " cd $PARENT_DIR && pnpm cypress" +echo "" +echo "To stop the test environment:" +echo " $SCRIPT_DIR/stop-test-environment.sh" +EOF + chmod +x "$SCRIPT_DIR/cypress/start-test-environment.sh" + log "Test environment startup script created and made executable" + fi + + if [ ! -f "$SCRIPT_DIR/cypress/stop-test-environment.sh" ]; then + log "Creating test environment shutdown script..." + cat > "$SCRIPT_DIR/cypress/stop-test-environment.sh" << 'EOF' +#!/bin/bash + +# Script to stop the test environment + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PARENT_DIR="$(dirname "$SCRIPT_DIR")" + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +echo -e "${YELLOW}Stopping MYP test environment...${NC}" + +# Function to run docker compose (handles both docker-compose and docker compose syntax) +run_docker_compose() { + if command -v docker-compose &> /dev/null; then + docker-compose "$@" + else + docker compose "$@" + fi +} + +# Stop the backend container +echo "Stopping backend containers..." +cd "$SCRIPT_DIR" +run_docker_compose -f docker-compose.test.yml down + +# Stop the frontend development server if we started it +if [ -f "$SCRIPT_DIR/frontend.pid" ]; then + FRONTEND_PID=$(cat "$SCRIPT_DIR/frontend.pid") + echo "Stopping frontend development server (PID: $FRONTEND_PID)..." + + if kill -0 $FRONTEND_PID 2>/dev/null; then + kill $FRONTEND_PID + echo "Frontend development server stopped" + else + echo "Frontend development server is not running with PID $FRONTEND_PID" + fi + + rm -f "$SCRIPT_DIR/frontend.pid" + rm -f "$SCRIPT_DIR/frontend.log" +else + echo "No frontend PID file found, assuming it was started externally" +fi + +echo -e "${GREEN}Test environment has been stopped${NC}" +EOF + chmod +x "$SCRIPT_DIR/cypress/stop-test-environment.sh" + log "Test environment shutdown script created and made executable" + fi + # Build Docker image with error handling log "Building Docker image (this may take a while)..." @@ -510,12 +1038,122 @@ AUTH_TRUST_HOST=true # Backend URL - Static IP for backend NEXT_PUBLIC_BACKEND_URL=http://192.168.0.105:5000 + +# Test environment +CYPRESS_TEST_USER=test-user EOF log "ATTENTION: Development environment file created with generated AUTH_SECRET" log " Backend URL set to http://192.168.0.105:5000" + log " Added Cypress test user configuration" log " Please edit $SCRIPT_DIR/.env.local with your actual GitHub OAuth credentials" fi + # Set up Cypress testing if it doesn't exist + if [ ! -f "$SCRIPT_DIR/cypress.config.ts" ]; then + log "Setting up Cypress configuration..." + cat > "$SCRIPT_DIR/cypress.config.ts" << EOF +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + baseUrl: 'http://localhost:3000', + supportFile: 'cypress/support/commands.ts', + specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}', + }, + component: { + devServer: { + framework: 'next', + bundler: 'webpack', + }, + }, + env: { + backendUrl: 'http://localhost:5000', + }, +}) +EOF + log "Cypress configuration created" + fi + + # Create Cypress support directory if it doesn't exist + if [ ! -d "$SCRIPT_DIR/cypress/support" ]; then + log "Creating Cypress support directory..." + mkdir -p "$SCRIPT_DIR/cypress/support" + fi + + # Add Cypress commands file if it doesn't exist + if [ ! -f "$SCRIPT_DIR/cypress/support/commands.ts" ]; then + log "Creating Cypress commands file..." + cat > "$SCRIPT_DIR/cypress/support/commands.ts" << EOF +// -- This is a parent command -- +Cypress.Commands.add('login', () => { + // Simulate logged in user without OAuth + window.localStorage.setItem('myp:user', JSON.stringify({ + id: 'test-user-id', + name: 'Test User', + email: 'test@example.com', + role: 'user' + })) +}) + +// -- This is a child command -- +Cypress.Commands.add('createPrintJob', (printerId, duration) => { + cy.intercept('POST', \`/api/printers/\${printerId}/reserve\`, { + id: 'test-job-id', + printerId, + userId: 'test-user-id', + startTime: new Date().toISOString(), + endTime: new Date(Date.now() + duration * 60000).toISOString(), + status: 'active' + }).as('createJob') + + return cy.wrap('test-job-id') +}) + +declare global { + namespace Cypress { + interface Chainable { + login(): Chainable + createPrintJob(printerId: string, duration: number): Chainable + } + } +} +EOF + log "Cypress commands file created" + fi + + # Create Cypress e2e directory if it doesn't exist + if [ ! -d "$SCRIPT_DIR/cypress/e2e" ]; then + log "Creating Cypress e2e directory..." + mkdir -p "$SCRIPT_DIR/cypress/e2e" + fi + + # Add Cypress example test file if it doesn't exist + if [ ! -f "$SCRIPT_DIR/cypress/e2e/home.cy.ts" ]; then + log "Creating Cypress example test file..." + cat > "$SCRIPT_DIR/cypress/e2e/home.cy.ts" << EOF +describe('Homepage', () => { + beforeEach(() => { + cy.visit('/') + }) + + it('loads the homepage successfully', () => { + cy.contains('Manage Your Printers') + cy.get('a[href="/printer"]').should('exist') + }) + + it('shows printer cards', () => { + cy.get('[class*="w-auto h-36"]').should('exist') + }) + + it('has working navigation', () => { + cy.get('header').should('exist') + cy.get('a[href="/"]').should('exist') + }) +}) +EOF + log "Cypress example test file created" + fi + # Create systemd service for development mode log "Creating systemd service for development mode..." cat > /etc/systemd/system/myp-frontend-dev.service << EOF @@ -568,6 +1206,19 @@ log " - Stop containers: docker-compose -f $SCRIPT_DIR/docker/compose.yml down" log " - Start containers: docker-compose -f $SCRIPT_DIR/docker/compose.yml up -d" log " - Restart containers: docker-compose -f $SCRIPT_DIR/docker/compose.yml restart" log "" +if [ "$test_environment" = "y" ] || [ "$test_environment" = "Y" ]; then + log "Test environment commands:" + log " - Run integration test: bash $SCRIPT_DIR/docker/test-integration.sh" + log " - View test logs: cat $SCRIPT_DIR/docker/test-integration.log" + log " - Stop test environment: docker-compose -f $SCRIPT_DIR/docker/test-env.yml down" +else + log "Testing environment:" + log " - Start test environment: cd $SCRIPT_DIR && pnpm test:start-environment" + log " - Run Cypress tests: cd $SCRIPT_DIR && pnpm cypress" + log " - Stop test environment: cd $SCRIPT_DIR && pnpm test:stop-environment" + log " - To install test environment: $0 --auto-test" +fi +log "" log "Backend connection:" log " - Test backend connection: curl -I http://192.168.0.105:5000/api/test" log " - Check backend accessibility: ping 192.168.0.105" diff --git a/packages/reservation-platform/package.json b/packages/reservation-platform/package.json index d3cc006..a77a4b1 100755 --- a/packages/reservation-platform/package.json +++ b/packages/reservation-platform/package.json @@ -8,6 +8,12 @@ "build": "next build", "start": "next start", "lint": "next lint", + "cypress": "cypress open", + "test": "cypress run", + "test:e2e": "start-server-and-test dev http://localhost:3000 test", + "test:start-environment": "bash cypress/start-test-environment.sh", + "test:stop-environment": "bash cypress/stop-test-environment.sh", + "test:with-backend": "bash cypress/start-test-environment.sh && cypress open && bash cypress/stop-test-environment.sh", "db:create-default": "mkdir -p db/", "db:generate-sqlite": "pnpm drizzle-kit generate", "db:clean": "rm -rf db/ drizzle/", @@ -74,8 +80,10 @@ "@types/node": "^20.16.11", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.1", + "cypress": "^13.6.6", "drizzle-kit": "^0.21.4", "postcss": "^8.4.47", + "start-server-and-test": "^2.2.0", "tailwindcss": "^3.4.13", "ts-node": "^10.9.2", "typescript": "^5.6.3"