# SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project # # SPDX-License-Identifier: Apache-2.0 name: Tests on: pull_request: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: changes: runs-on: ubuntu-latest outputs: base: ${{ steps.filter.outputs.base }} core: ${{ steps.filter.outputs.core }} server: ${{ steps.filter.outputs.server }} operator-ui: ${{ steps.filter.outputs.operator-ui }} shared: ${{ steps.filter.outputs.shared }} steps: - uses: actions/checkout@v4 - uses: dorny/paths-filter@v3 id: filter with: filters: | shared: - 'pnpm-lock.yaml' - 'pnpm-workspace.yaml' - 'package.json' - 'tsconfig*.json' - 'vitest.config.ts' - 'eslint.config.base.js' - '.github/workflows/**' base: - 'packages/base/**' core: - 'packages/core/**' - 'packages/base/**' server: - 'apps/Server/**' - 'packages/**' operator-ui: - 'apps/operator-ui/**' - 'packages/base/**' tests: needs: changes if: ${{ needs.changes.outputs.base == 'true' || needs.changes.outputs.core == 'true' || needs.changes.outputs.server == 'true' || needs.changes.outputs.shared == 'true' }} runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 10.19.0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "24.16.0" cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Build run: pnpm run build - name: Run tests env: NODE_OPTIONS: "--max_old_space_size=4096" run: pnpm test operator-ui-e2e: needs: changes if: ${{ needs.changes.outputs.operator-ui == 'true' || needs.changes.outputs.shared == 'true' }} runs-on: ubuntu-latest timeout-minutes: 45 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 10.19.0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "24.16.0" cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Build @citrineos/operator-ui and its workspace deps run: pnpm --filter "@citrineos/operator-ui..." run build - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ hashFiles('apps/operator-ui/package.json') }} - name: Install Playwright browsers if: steps.playwright-cache.outputs.cache-hit != 'true' working-directory: apps/operator-ui run: pnpm exec playwright install --with-deps chromium - name: Install Playwright system deps if: steps.playwright-cache.outputs.cache-hit == 'true' working-directory: apps/operator-ui run: pnpm exec playwright install-deps chromium - name: Start backend stack (Hasura + CitrineOS Core) # Build with the default docker driver (builds straight into the daemon's # image store) — no tarball export/import or cache round-trip, which is # what made the build-push-action approach ~3min slower than the build itself. run: docker compose -f ${{ github.workspace }}/apps/Server/docker-compose.yml up -d --build - name: Wait for backend healthy run: | set -e for i in $(seq 1 60); do HASURA_OK=$(curl -fs http://localhost:8090/healthz > /dev/null && echo yes || echo no) CORE_OK=$(curl -fs http://localhost:8080/health > /dev/null && echo yes || echo no) if [ "$HASURA_OK" = "yes" ] && [ "$CORE_OK" = "yes" ]; then echo "Backend healthy after ${i} attempts." exit 0 fi echo "Waiting for backend (attempt ${i}/60): hasura=${HASURA_OK} core=${CORE_OK}" sleep 5 done echo "Backend did not become healthy in time." exit 1 - name: Run operator-ui Playwright tests env: CI: "true" NODE_OPTIONS: "--max_old_space_size=4096" NEXT_PUBLIC_ADMIN_EMAIL: admin@citrineos.com ADMIN_PASSWORD: CitrineOS! NEXTAUTH_URL: http://localhost:3000 NEXTAUTH_SECRET: test-secret-for-e2e-only HASURA_ADMIN_SECRET: CitrineOS! NEXT_PUBLIC_API_URL: http://localhost:8090/v1/graphql NEXT_PUBLIC_WS_URL: ws://localhost:8090/v1/graphql NEXT_PUBLIC_CITRINE_CORE_URL: http://localhost:8080 NEXT_PUBLIC_FILE_SERVER_URL: http://localhost:8050 ALLOW_IMAGE_UPLOAD: "false" working-directory: apps/operator-ui run: pnpm exec playwright test --project=chromium-desktop - name: Upload Playwright report if: always() uses: actions/upload-artifact@v4 with: name: operator-ui-playwright-report path: | apps/operator-ui/playwright-report apps/operator-ui/test-results apps/operator-ui/reports retention-days: 7 - name: Dump backend logs on failure if: failure() run: | docker ps -a docker container ls -aq | xargs -I {} docker logs {} || true - name: Tear down backend stack if: always() run: docker compose -f ${{ github.workspace }}/apps/Server/docker-compose.yml down -v