Skip to content

E2E Tests

E2E Tests #27

Workflow file for this run

# Copyright (C) Siemens AG, 2026. Part of the SW360 Frontend Project.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
# License-Filename: LICENSE
name: E2E Tests
on:
pull_request:
paths:
- 'src/**'
- 'messages/**'
- 'tests/**'
schedule:
- cron: '0 2 * * *' # Daily at 2 AM UTC (runs on main)
workflow_dispatch:
inputs:
module:
description: 'Test module to run (empty = all). Access control tests always run.'
required: false
type: choice
options:
- ''
- projects
- components
- licenses
- packages
- vulnerabilities
- search
- home
- admin
- ecc
- preferences
- requests
permissions:
contents: read
jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Checkout source code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Determine test scope
id: scope
run: |
# workflow_dispatch: use selected module
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.module }}" ]; then
echo "modules=${{ inputs.module }}" >> $GITHUB_OUTPUT
echo "📋 Running module: ${{ inputs.module }} (from workflow_dispatch)"
exit 0
fi
# schedule (cron on main): run everything
if [ "${{ github.event_name }}" = "schedule" ]; then
echo "modules=" >> $GITHUB_OUTPUT
echo "📋 Running all modules (scheduled nightly on main)"
exit 0
fi
# pull_request: detect affected modules from changed files
echo "📋 Detecting affected modules from PR changed files..."
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }}...${{ github.sha }} 2>/dev/null || git diff --name-only HEAD~1)
MODULES=""
add_module() {
if ! echo "$MODULES" | grep -qw "$1"; then
MODULES="${MODULES:+$MODULES }$1"
fi
}
# Check if shared/core code changed → run all
SHARED_PATTERN="^(src/components/sw360/|src/utils/|src/services/|src/hooks/|src/object-types/|src/contexts/|src/styles/|src/navigation\.|src/proxy\.|next\.config|tests/config\.ts|tests/e2e/auth\.setup\.ts|playwright\.config)"
if echo "$CHANGED_FILES" | grep -qE "$SHARED_PATTERN"; then
echo " ⚡ Shared code changed — running all modules"
echo "modules=" >> $GITHUB_OUTPUT
exit 0
fi
# Map source paths to test modules
for file in $CHANGED_FILES; do
case "$file" in
src/app/*/projects/*|src/components/ProjectAddSummary/*|tests/e2e/projects/*) add_module "projects" ;;
src/app/*/components/*|tests/e2e/components/*) add_module "components" ;;
src/app/*/licenses/*|tests/e2e/licenses/*) add_module "licenses" ;;
src/app/*/packages/*|tests/e2e/packages/*) add_module "packages" ;;
src/app/*/vulnerabilities/*|src/components/ComponentVulnerabilities/*|tests/e2e/vulnerabilities/*) add_module "vulnerabilities" ;;
src/app/*/search/*|tests/e2e/search/*) add_module "search" ;;
src/app/*/home/*|tests/e2e/home/*) add_module "home" ;;
src/app/*/admin/*|tests/e2e/admin/*) add_module "admin" ;;
src/app/*/ecc/*|tests/e2e/ecc/*) add_module "ecc" ;;
src/app/*/preferences/*|tests/e2e/preferences/*) add_module "preferences" ;;
src/app/*/requests/*|tests/e2e/requests/*) add_module "requests" ;;
esac
done
if [ -z "$MODULES" ]; then
echo " ℹ️ No module-specific changes detected — running all"
else
echo " 🎯 Affected modules: $MODULES"
fi
echo "modules=$MODULES" >> $GITHUB_OUTPUT
- name: Setup pnpm
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
with:
version: 11
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Build frontend
env:
NEXT_PUBLIC_SW360_API_URL: http://localhost:8080
NEXT_PUBLIC_SW360_AUTH_PROVIDER: sw360basic
NEXTAUTH_URL: http://localhost:3000
AUTH_SECRET: mysecret
run: pnpm build
- name: Start backend services (SW360 + CouchDB)
run: |
# Start only backend services (not sw360-frontend — we use our built version)
docker compose -f docker-compose.yml up -d sw360 couchdb couchdb-nouveau
echo "⏳ Waiting for CouchDB..."
timeout 60 bash -c 'until curl -fsS http://localhost:5984/_up >/dev/null 2>&1; do sleep 3; done'
echo "✅ CouchDB is ready"
echo "⏳ Waiting for SW360 backend (this may take 4-5 minutes)..."
timeout 600 bash -c 'until curl -fsS http://localhost:8080/resource/api/health 2>/dev/null | grep -iq "status.*up"; do sleep 5; done'
echo "✅ SW360 backend is healthy"
# Verify the REST API actually accepts authenticated requests (DB init may lag behind health)
SW360_TOKEN=$(echo -n "setup@sw360.org:sw360fossie" | base64)
echo "⏳ Verifying REST API accepts authenticated requests..."
timeout 120 bash -c "
until curl -sS -o /dev/null -w '%{http_code}' \
-H 'Authorization: Basic ${SW360_TOKEN}' \
http://localhost:8080/resource/api/users/setup@sw360.org 2>/dev/null | grep -q '200'; do
echo ' ...backend not ready yet, retrying in 5s'
sleep 5
done
"
echo "✅ Backend REST API is responding to authenticated requests"
# Verify write operations work (POST a test project, then delete it)
echo "⏳ Verifying write operations..."
HEALTHCHECK_NAME="e2ehealthcheck$(date +%s)"
timeout 60 bash -c "
until RESPONSE=\$(curl -sS -w '\\n%{http_code}' \
-X POST http://localhost:8080/resource/api/projects \
-H 'Authorization: Basic ${SW360_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{\"name\":\"'\"${HEALTHCHECK_NAME}\"'\",\"version\":\"1.0\"}' 2>/dev/null) && \
echo \"\$RESPONSE\" | tail -1 | grep -q '201'; do
echo ' ...write operations not ready yet, retrying in 5s'
sleep 5
done
"
PROJECT_URL=$(curl -sS \
-H "Authorization: Basic ${SW360_TOKEN}" \
"http://localhost:8080/resource/api/projects?name=${HEALTHCHECK_NAME}" 2>/dev/null \
| grep -o '"href":"[^"]*"' | head -1 | cut -d'"' -f4)
echo "✅ Backend write operations verified"
# Clean up the test project
if [ -n "$PROJECT_URL" ]; then
curl -sS -X DELETE "$PROJECT_URL" -H "Authorization: Basic ${SW360_TOKEN}" >/dev/null 2>&1 || true
fi
echo "✅ All backend checks passed — ready for E2E tests"
- name: Start frontend (production mode)
run: |
pnpm start &
echo "⏳ Waiting for Next.js..."
timeout 30 bash -c 'until curl -fsS http://localhost:3000 >/dev/null 2>&1; do sleep 2; done'
echo "✅ Frontend is ready"
env:
NEXT_PUBLIC_SW360_API_URL: http://localhost:8080
NEXT_PUBLIC_SW360_AUTH_PROVIDER: sw360basic
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: mysecret
- name: Run E2E tests
run: |
MODULES="${{ steps.scope.outputs.modules }}"
if [ -n "$MODULES" ]; then
# Build test paths from space-separated module list
TEST_PATHS=""
for mod in $MODULES; do
TEST_PATHS="$TEST_PATHS tests/e2e/$mod/"
done
echo "🧪 Running tests for: $MODULES"
npx playwright test $TEST_PATHS --project=chromium
else
echo "🧪 Running all E2E tests (standard modules)"
npx playwright test \
tests/e2e/projects/ \
tests/e2e/components/ \
tests/e2e/licenses/ \
tests/e2e/packages/ \
tests/e2e/vulnerabilities/ \
tests/e2e/search/ \
tests/e2e/home/ \
tests/e2e/admin/ \
tests/e2e/ecc/ \
tests/e2e/preferences/ \
tests/e2e/requests/ \
--project=chromium
fi
# Always run accessControl tests with role-based projects
echo "🔐 Running accessControl tests with role-based projects"
npx playwright test tests/e2e/accessControl/ \
--project=chromium-user \
--project=chromium-viewer \
--project=chromium-clearing
env:
CI: true
ENABLE_ROLE_TESTS: 'true'
SKIP_ADMIN_TESTS: 'true'
SW360_BASE_URL: http://localhost:3000
SW360_API_URL: http://localhost:8080
SW360_TEST_ADMIN_EMAIL: setup@sw360.org
SW360_TEST_ADMIN_PASSWORD: sw360fossie
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report
path: tests/reports/
retention-days: 14
- name: Upload test screenshots & traces (on failure)
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: tests/results/
retention-days: 7
- name: Report viewing instructions
if: always()
run: |
echo "📊 To view the HTML report with screenshots:"
echo " 1. Download the 'playwright-report' artifact"
echo " 2. Extract the zip"
echo " 3. Run: npx playwright show-report <extracted-folder>"
echo ""
echo "📸 Failed test screenshots can be viewed directly in the 'test-results' artifact"
- name: Print backend logs (on failure)
if: failure()
run: |
echo "=== Running containers ==="
docker compose -f docker-compose.yml ps -a || true
echo ""
echo "=== Nouveau Diagnostic ==="
echo "Checking Nouveau container internals..."
docker compose -f docker-compose.yml exec -T couchdb-nouveau ls -la /opt/nouveau/data 2>&1 || echo "Could not list /opt/nouveau/data"
docker compose -f docker-compose.yml exec -T couchdb-nouveau cat /opt/nouveau/etc/nouveau.yaml 2>&1 || echo "Could not read nouveau.yaml"
echo ""
echo "=== SW360 Backend Logs (last 500 lines) ==="
docker compose -f docker-compose.yml logs --tail 500 sw360 2>&1 || echo "Failed to retrieve sw360 logs"
echo ""
echo "=== CouchDB Nouveau Logs (FULL) ==="
docker compose -f docker-compose.yml logs couchdb-nouveau 2>&1 || echo "Failed to retrieve couchdb-nouveau logs"
echo ""
echo "=== CouchDB Logs (last 300 lines) ==="
docker compose -f docker-compose.yml logs --tail 300 couchdb 2>&1 || echo "Failed to retrieve couchdb logs"
- name: Stop backend services
if: always()
run: docker compose -f docker-compose.yml down -v