Add Playwright e2e QA suite for Playground testing #127
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [ main ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # PHP — lint + test across PHP 8.2 / 8.3 / 8.4 | |
| # --------------------------------------------------------------------------- | |
| php: | |
| name: PHP ${{ matrix.php }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| php: [ '8.2', '8.3', '8.4' ] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up PHP ${{ matrix.php }} | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: ${{ matrix.php }} | |
| extensions: zip, mbstring | |
| coverage: none | |
| ini-values: memory_limit=1G | |
| - name: Get Composer cache directory | |
| id: composer-cache | |
| run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" | |
| - name: Cache Composer packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ steps.composer-cache.outputs.dir }} | |
| key: ${{ runner.os }}-composer-php${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} | |
| restore-keys: ${{ runner.os }}-composer-php${{ matrix.php }}- | |
| - name: Install Composer dependencies | |
| run: composer install --prefer-dist --no-progress | |
| - name: PHPCS lint | |
| run: composer phpcs | |
| - name: PHPStan analyse | |
| run: composer phpstan | |
| - name: PHPUnit tests | |
| run: composer test | |
| # --------------------------------------------------------------------------- | |
| # Release zip — built on every push to main, uploaded on tagged releases | |
| # --------------------------------------------------------------------------- | |
| release-zip: | |
| name: Release zip | |
| runs-on: ubuntu-latest | |
| needs: [ php, js, test-wares ] | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up PHP 8.2 | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.2' | |
| extensions: zip, mbstring | |
| coverage: none | |
| - name: Set up Node 24 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Install npm dependencies | |
| run: npm ci | |
| - name: Build release zip | |
| run: bash bin/build-zip.sh | |
| - name: Verify autoloader is present | |
| run: | | |
| unzip -l dist/bazaar-*.zip | grep vendor/autoload.php | |
| echo "✓ vendor/autoload.php present in zip" | |
| - name: Verify no dev packages in zip | |
| run: | | |
| if unzip -l dist/bazaar-*.zip | grep -q 'vendor/phpunit\|vendor/phpstan\|vendor/squizlabs\|vendor/brain'; then | |
| echo "ERROR: dev packages found in zip" >&2 | |
| exit 1 | |
| fi | |
| echo "✓ No dev packages in zip" | |
| - name: Upload zip artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: bazaar-zip | |
| path: dist/bazaar-*.zip | |
| - name: Attach zip to GitHub release | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh release create "${GITHUB_REF_NAME}" --generate-notes --title "${GITHUB_REF_NAME}" || true | |
| gh release upload "${GITHUB_REF_NAME}" dist/bazaar-*.zip --clobber | |
| cp dist/bazaar-*.zip dist/bazaar.zip | |
| gh release upload "${GITHUB_REF_NAME}" dist/bazaar.zip --clobber | |
| # --------------------------------------------------------------------------- | |
| # JS — lint + build + test (Node 24) | |
| # --------------------------------------------------------------------------- | |
| js: | |
| name: JS / Node 24 | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Node 24 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Install npm dependencies | |
| run: npm ci | |
| - name: JS lint | |
| run: npm run lint | |
| - name: Build | |
| run: npm run build | |
| - name: JS tests | |
| run: npm test | |
| - name: TypeScript check (wares + packages) | |
| run: npm run typecheck | |
| # --------------------------------------------------------------------------- | |
| # Coverage — PHP clover + JS lcov (runs only after php + js are green) | |
| # --------------------------------------------------------------------------- | |
| coverage: | |
| name: Coverage report | |
| runs-on: ubuntu-latest | |
| needs: [ php, js ] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up PHP 8.2 with pcov | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.2' | |
| extensions: zip, mbstring | |
| coverage: pcov | |
| ini-values: memory_limit=1G | |
| - name: Set up Node 24 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Get Composer cache directory | |
| id: composer-cache | |
| run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" | |
| - name: Cache Composer packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ steps.composer-cache.outputs.dir }} | |
| key: ${{ runner.os }}-composer-php8.2-${{ hashFiles('**/composer.lock') }} | |
| restore-keys: ${{ runner.os }}-composer-php8.2- | |
| - name: Install Composer dependencies | |
| run: composer install --prefer-dist --no-progress | |
| - name: Install npm dependencies | |
| run: npm ci | |
| - name: PHP tests with clover coverage | |
| run: composer test -- --coverage-clover coverage/clover.xml | |
| - name: JS tests with lcov coverage | |
| run: npm test -- --coverage --coverageDirectory=coverage/js | |
| - name: Upload coverage reports | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage | |
| path: coverage/ | |
| retention-days: 14 | |
| # --------------------------------------------------------------------------- | |
| # Test wares — Vitest unit + component tests for all 7 React wares | |
| # --------------------------------------------------------------------------- | |
| test-wares: | |
| name: Test wares | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Node 24 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Install all workspace dependencies | |
| env: | |
| HUSKY: '0' | |
| run: npm ci | |
| - name: Build @bazaar/client | |
| working-directory: packages/client | |
| run: npm run build | |
| - name: Test board | |
| working-directory: wares/board | |
| run: npm test | |
| - name: Test flow | |
| working-directory: wares/flow | |
| run: npm test | |
| - name: Test ledger | |
| working-directory: wares/ledger | |
| run: npm test | |
| - name: Test mosaic | |
| working-directory: wares/mosaic | |
| run: npm test | |
| - name: Test sine | |
| working-directory: wares/sine | |
| run: npm test | |
| - name: Test swatch | |
| working-directory: wares/swatch | |
| run: npm test | |
| - name: Test tome | |
| working-directory: wares/tome | |
| run: npm test | |
| # --------------------------------------------------------------------------- | |
| # Build wares — compile and package all .wp files | |
| # --------------------------------------------------------------------------- | |
| build-wares: | |
| name: Build wares | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Node 24 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Install all workspace dependencies | |
| env: | |
| HUSKY: '0' | |
| run: npm ci | |
| - name: Build packages/design | |
| working-directory: packages/design | |
| run: npm run build | |
| - name: Build packages/client | |
| working-directory: packages/client | |
| run: npm run build | |
| - name: Build mosaic | |
| working-directory: wares/mosaic | |
| run: npm run package | |
| - name: Build ledger | |
| working-directory: wares/ledger | |
| run: npm run package | |
| - name: Build flow | |
| working-directory: wares/flow | |
| run: npm run package | |
| - name: Build board | |
| working-directory: wares/board | |
| run: npm run package | |
| - name: Build swatch | |
| working-directory: wares/swatch | |
| run: npm run package | |
| - name: Build sine | |
| working-directory: wares/sine | |
| run: npm run package | |
| - name: Build tome | |
| working-directory: wares/tome | |
| run: npm run package | |
| - name: Verify .wp files | |
| run: | | |
| for f in wares/*.wp; do | |
| echo "✓ $f ($(du -sh "$f" | cut -f1))" | |
| unzip -l "$f" | grep manifest.json | |
| done | |
| - name: Upload ware artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wares | |
| path: wares/*.wp | |
| retention-days: 30 | |
| # --------------------------------------------------------------------------- | |
| # E2E — Playwright smoke tests against a real WordPress environment | |
| # Runs only on main and tag pushes to avoid heavy setup on every PR. | |
| # --------------------------------------------------------------------------- | |
| e2e: | |
| name: E2E smoke tests | |
| runs-on: ubuntu-latest | |
| needs: [ php, js ] | |
| if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up PHP 8.2 | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.2' | |
| extensions: zip, mbstring | |
| coverage: none | |
| - name: Set up Node 24 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Install npm dependencies | |
| env: | |
| HUSKY: '0' | |
| run: npm ci | |
| - name: Install Composer dependencies (production autoloader) | |
| run: composer install --prefer-dist --no-progress | |
| - name: Build admin JS bundle | |
| run: npm run build | |
| # wp-env mounts the current directory as the plugin (see .wp-env.json). | |
| # Building here ensures the compiled admin shell assets are present. | |
| - name: Start wp-env | |
| run: npx wp-env start | |
| timeout-minutes: 5 | |
| # .wp-env.json has "plugins": ["."] so the plugin is auto-installed | |
| # and activated from the current working directory — no manual install needed. | |
| - name: Install Playwright browsers | |
| run: npx playwright install chromium --with-deps | |
| - name: Run E2E smoke tests | |
| run: npm run test:e2e | |
| - name: Upload Playwright report | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-report | |
| path: playwright-report/ | |
| retention-days: 7 | |
| - name: Stop wp-env | |
| if: always() | |
| run: npx wp-env stop | |
| # --------------------------------------------------------------------------- | |
| # Deploy Playground assets to GitHub Pages (gh-pages branch) on every tag. | |
| # GitHub Pages serves with Access-Control-Allow-Origin: * so Playground's | |
| # browser-based fetch can download the zip and .wp files without CORS errors. | |
| # blueprint.json points to stable versionless URLs on this Pages site so it | |
| # never needs to be updated for version bumps. | |
| # --------------------------------------------------------------------------- | |
| deploy-playground: | |
| name: Deploy Playground assets | |
| runs-on: ubuntu-latest | |
| needs: [ release-zip, build-wares ] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: gh-pages | |
| token: ${{ github.token }} | |
| - name: Download plugin zip artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: bazaar-zip | |
| path: /tmp/artifacts/ | |
| - name: Download ware artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: wares | |
| path: /tmp/artifacts/ | |
| - name: Copy assets into gh-pages root | |
| run: | | |
| # Ensure Jekyll is bypassed so GitHub Pages serves files directly | |
| touch .nojekyll | |
| # The versioned zip (bazaar-1.x.y.zip) becomes the stable bazaar.zip | |
| find /tmp/artifacts -name 'bazaar-*.zip' | head -1 | xargs -I{} cp {} ./bazaar.zip | |
| for WARE in board flow ledger mosaic sine swatch tome; do | |
| cp /tmp/artifacts/${WARE}.wp ./${WARE}.wp | |
| done | |
| - name: Commit and push to gh-pages | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add .nojekyll bazaar.zip board.wp flow.wp ledger.wp mosaic.wp sine.wp swatch.wp tome.wp | |
| if git diff --cached --quiet; then | |
| echo "Assets already up to date." | |
| else | |
| git commit -m "deploy: ${GITHUB_REF_NAME} playground assets [skip ci]" | |
| git push origin gh-pages | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Attach wares to GitHub release on v* tags | |
| # --------------------------------------------------------------------------- | |
| release-wares: | |
| name: Release wares | |
| runs-on: ubuntu-latest | |
| needs: [ build-wares ] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Download ware artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: wares | |
| path: wares-dist/ | |
| - name: Copy ware icons to release assets | |
| run: | | |
| cp wares/mosaic/public/icon.svg wares-dist/mosaic-icon.svg | |
| cp wares/ledger/public/icon.svg wares-dist/ledger-icon.svg | |
| cp wares/flow/public/icon.svg wares-dist/flow-icon.svg | |
| cp wares/board/public/icon.svg wares-dist/board-icon.svg | |
| cp wares/swatch/public/icon.svg wares-dist/swatch-icon.svg | |
| cp wares/sine/public/icon.svg wares-dist/sine-icon.svg | |
| cp wares/tome/public/icon.svg wares-dist/tome-icon.svg | |
| - name: Attach wares to release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh release create "${GITHUB_REF_NAME}" --generate-notes --title "${GITHUB_REF_NAME}" || true | |
| gh release upload "${GITHUB_REF_NAME}" wares-dist/* --clobber | |
| # --------------------------------------------------------------------------- | |
| # Sync docs/ → GitHub Wiki on every push to main | |
| # --------------------------------------------------------------------------- | |
| sync-wiki: | |
| name: Sync wiki | |
| runs-on: ubuntu-latest | |
| needs: [ php, js ] | |
| if: github.ref == 'refs/heads/main' | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Clone wiki repo | |
| run: git clone https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.wiki.git /tmp/wiki | |
| - name: Copy docs into wiki (skip internal files) | |
| run: | | |
| # Copy every .md in docs/ except internal/audit files | |
| for f in docs/*.md; do | |
| base=$(basename "$f") | |
| case "$base" in | |
| 10-pass-audit-todos.md) continue ;; | |
| esac | |
| cp "$f" /tmp/wiki/"$base" | |
| done | |
| - name: Commit and push if anything changed | |
| run: | | |
| cd /tmp/wiki | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| if git diff --cached --quiet; then | |
| echo "No wiki changes." | |
| else | |
| git commit -m "docs: sync from docs/ @ ${{ github.sha }}" | |
| git push | |
| fi |