name: Start Sencho App description: > Shared setup for integration jobs: installs deps, builds backend, starts backend + frontend dev servers, waits for readiness, and installs Playwright browsers. inputs: jwt-secret: required: false default: 'ci-test-secret-key-not-for-production' compose-dir: required: false default: '/tmp/compose' port: required: false default: '1852' skip-backend-build: description: > When 'true', skip running `npm run build` in backend/ and assume the caller has already materialized backend/dist (e.g. via download-artifact from an upstream job that already built and verified it). Leave 'false' for standalone invocations that do not run in a job graph with a prior build step. required: false default: 'false' runs: using: composite steps: - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6 with: node-version-file: '.node-version' cache: 'npm' cache-dependency-path: | package-lock.json backend/package-lock.json frontend/package-lock.json - name: Install root dependencies (Playwright) shell: bash run: npm ci - name: Install backend dependencies shell: bash run: npm ci working-directory: ./backend - name: Build backend if: inputs.skip-backend-build != 'true' shell: bash run: npm run build working-directory: ./backend - name: Install frontend dependencies shell: bash run: npm ci working-directory: ./frontend - name: Create compose directory and log dir shell: bash run: | mkdir -p ${{ inputs.compose-dir }} mkdir -p "${{ github.workspace }}/ci-logs" # Log files live under $GITHUB_WORKSPACE so actions/upload-artifact@v4+ can # include them alongside repo-relative paths like e2e/report/. Mixing those # with /tmp paths makes '/' the common root and v4+ strips the absolute # entries from the artifact. `stdbuf -oL -eL` forces line-buffered output # so a crash doesn't lose the final few hundred lines to block buffering. - name: Start backend shell: bash run: stdbuf -oL -eL node dist/index.js > "${{ github.workspace }}/ci-logs/backend.log" 2>&1 & working-directory: ./backend env: JWT_SECRET: ${{ inputs.jwt-secret }} COMPOSE_DIR: ${{ inputs.compose-dir }} PORT: ${{ inputs.port }} NODE_ENV: test - name: Start frontend dev server shell: bash run: stdbuf -oL -eL npm run dev > "${{ github.workspace }}/ci-logs/frontend.log" 2>&1 & working-directory: ./frontend - name: Wait for services to be ready shell: bash run: npx wait-on http://localhost:${{ inputs.port }}/api/health http://localhost:5173 --timeout 30000 # Playwright bundles Chrome for Testing (~170MB) and FFmpeg. Downloading # them on every E2E run is the single largest cost in this composite: # observed ~4m15s cold vs ~10s warm when the path is cached. Cache the # download under a key pinned to the @playwright/test version so a # future bump invalidates automatically. - name: Read Playwright version id: playwright-version shell: bash run: | version=$(node -p "require('./package.json').devDependencies['@playwright/test'].replace(/^[\^~]/, '')") echo "version=$version" >> "$GITHUB_OUTPUT" - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }} # OS deps are apt packages under /var, which actions/cache does not # preserve, so they have to be reinstalled every run regardless of the # browser cache state. It is fast (~10s). - name: Install Playwright OS dependencies shell: bash run: npx playwright install-deps chromium - name: Install Playwright browsers if: steps.playwright-cache.outputs.cache-hit != 'true' shell: bash run: npx playwright install chromium