Skip to content

Add Playwright e2e QA suite for Playground testing #127

Add Playwright e2e QA suite for Playground testing

Add Playwright e2e QA suite for Playground testing #127

Workflow file for this run

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