-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add visual regression testing workflow #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,210 @@ | ||
| name: Reusable WP Visual Regression | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| node-version: | ||
| description: 'Node.js version' | ||
| required: false | ||
| type: string | ||
| default: '22' | ||
| wp-versions: | ||
| description: 'JSON array of WP versions (e.g. "latest", "6.7")' | ||
| required: false | ||
| type: string | ||
| default: '["latest"]' | ||
| multisite: | ||
| description: 'Multisite mode: "none", "both", or "only"' | ||
| required: false | ||
| type: string | ||
| default: 'none' | ||
| mailpit: | ||
| description: 'Run Mailpit mail catcher (SMTP on :1025, UI on :8025)' | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| update-snapshots: | ||
| description: 'Regenerate baseline screenshots' | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| threshold: | ||
| description: 'Pixel diff tolerance as maxDiffPixelRatio (0-1)' | ||
| required: false | ||
| type: string | ||
| default: '0.2' | ||
| viewports: | ||
| description: 'JSON array of viewport presets (e.g. ["desktop", "mobile"])' | ||
| required: false | ||
| type: string | ||
| default: '["desktop", "mobile"]' | ||
| color-schemes: | ||
| description: 'JSON array of color scheme presets (e.g. ["light", "dark"])' | ||
| required: false | ||
| type: string | ||
| default: '["light"]' | ||
|
|
||
| jobs: | ||
| matrix-prep: | ||
| name: Prepare matrix | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| wp-versions: ${{ steps.wp-versions.outputs.matrix }} | ||
| multisite: ${{ steps.multisite.outputs.matrix }} | ||
| steps: | ||
| - id: wp-versions | ||
| run: | | ||
| MATRIX=$(echo '${{ inputs.wp-versions }}' | jq -c '[.[] | if . == "latest" then {"input": "latest", "core": "null"} else {"input": ., "core": ("WordPress/WordPress#" + .)} end]') | ||
| echo "matrix=${MATRIX}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - id: multisite | ||
| run: | | ||
| case "${{ inputs.multisite }}" in | ||
| both) echo "matrix=[false, true]" >> "$GITHUB_OUTPUT" ;; | ||
| only) echo "matrix=[true]" >> "$GITHUB_OUTPUT" ;; | ||
| *) echo "matrix=[false]" >> "$GITHUB_OUTPUT" ;; | ||
| esac | ||
|
|
||
| visual-regression: | ||
| name: WP ${{ matrix.wp.input }}${{ matrix.multisite && ' / multisite' || '' }} | ||
| needs: matrix-prep | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| wp: ${{ fromJson(needs.matrix-prep.outputs.wp-versions) }} | ||
| multisite: ${{ fromJson(needs.matrix-prep.outputs.multisite) }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| lfs: true | ||
|
|
||
| - uses: shivammathur/setup-php@v2 | ||
| with: | ||
| php-version: '8.4' | ||
| coverage: none | ||
|
|
||
| - name: Install Composer dependencies | ||
| if: hashFiles('composer.json') != '' | ||
| run: composer install --no-interaction --prefer-dist | ||
|
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ inputs.node-version }} | ||
| cache: npm | ||
|
|
||
| - name: Install Node.js dependencies | ||
| run: | | ||
| if [ -f package-lock.json ]; then | ||
| npm ci | ||
| else | ||
| npm install | ||
| fi | ||
|
|
||
| - name: Install wp-env | ||
| run: npm install -g @wordpress/env | ||
|
|
||
| - name: Validate wp-env configuration | ||
| run: | | ||
| if [ ! -f .wp-env.json ]; then | ||
| echo "::error::Missing .wp-env.json in repository root. See https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Configure wp-env override | ||
| if: matrix.wp.core != 'null' | ||
| run: | | ||
| echo '{ "core": "${{ matrix.wp.core }}" }' > .wp-env.override.json | ||
|
|
||
| - name: Start wp-env | ||
| run: npx wp-env start | ||
|
|
||
| - name: Convert to multisite | ||
| if: matrix.multisite | ||
| run: npx wp-env run cli wp core multisite-convert --title="Test Site" | ||
|
|
||
| - name: Start Mailpit | ||
| if: inputs.mailpit | ||
| run: | | ||
| docker run -d --name mailpit \ | ||
| -p 1025:1025 \ | ||
| -p 8025:8025 \ | ||
| axllent/mailpit:latest | ||
|
|
||
| WP_CONTAINER=$(docker ps --format '{{.ID}}' --filter "name=wordpress" --no-trunc | head -1) | ||
| if [ -z "$WP_CONTAINER" ]; then | ||
| echo "::error::Could not find wp-env WordPress container" | ||
| exit 1 | ||
| fi | ||
| WP_NETWORK=$(docker inspect -f '{{range $k, $_ := .NetworkSettings.Networks}}{{$k}} {{end}}' "$WP_CONTAINER" | awk '{print $1}') | ||
| docker network connect "$WP_NETWORK" mailpit | ||
|
|
||
| - name: Configure WordPress SMTP for Mailpit | ||
| if: inputs.mailpit | ||
| run: | | ||
|
Check warning on line 144 in .github/workflows/reusable-wp-visual-regression.yml
|
||
| npx wp-env run cli wp eval ' | ||
| $dir = ABSPATH . "wp-content/mu-plugins"; | ||
| if (!is_dir($dir)) { mkdir($dir, 0755, true); } | ||
| file_put_contents($dir . "/mailpit-smtp.php", | ||
| "<?php\n" | ||
| . "add_filter(\"wp_mail_from\", function(\$email) {\n" | ||
| . " if (strpos(\$email, \"@localhost\") !== false) {\n" | ||
| . " return \"wordpress@example.tld\";\n" | ||
| . " }\n" | ||
| . " return \$email;\n" | ||
| . "});\n" | ||
| . "add_action(\"phpmailer_init\", function(\$phpmailer) {\n" | ||
| . " \$phpmailer->isSMTP();\n" | ||
| . " \$phpmailer->Host = \"mailpit\";\n" | ||
| . " \$phpmailer->Port = 1025;\n" | ||
| . " \$phpmailer->SMTPAutoTLS = false;\n" | ||
| . " \$phpmailer->SMTPAuth = false;\n" | ||
| . "});\n" | ||
| ); | ||
| ' | ||
|
|
||
| - name: Install Playwright browsers | ||
| run: npx playwright install --with-deps chromium | ||
|
|
||
| - name: Run visual regression tests | ||
| run: | | ||
| ARGS="" | ||
| if [ "${{ inputs.update-snapshots }}" = "true" ]; then | ||
| ARGS="--update-snapshots" | ||
| fi | ||
| npx playwright test $ARGS | ||
| env: | ||
| WP_BASE_URL: http://localhost:8888 | ||
| WP_ADMIN_USER: admin | ||
| WP_ADMIN_PASSWORD: password | ||
| VRT_THRESHOLD: ${{ inputs.threshold }} | ||
| VRT_VIEWPORTS: ${{ inputs.viewports }} | ||
| VRT_COLOR_SCHEMES: ${{ inputs.color-schemes }} | ||
| MAILPIT_API_URL: ${{ inputs.mailpit && 'http://localhost:8025' || '' }} | ||
|
|
||
| - name: Upload visual diff artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| if: failure() | ||
| with: | ||
| name: visual-regression-diffs-wp${{ matrix.wp.input }}${{ matrix.multisite && '-multisite' || '' }} | ||
| path: test-results/ | ||
| retention-days: 14 | ||
|
|
||
| - name: Upload updated snapshots | ||
| uses: actions/upload-artifact@v4 | ||
| if: inputs.update-snapshots | ||
| with: | ||
| name: updated-snapshots-wp${{ matrix.wp.input }}${{ matrix.multisite && '-multisite' || '' }} | ||
| path: | | ||
| **/__screenshots__/ | ||
| **/screenshots/ | ||
| retention-days: 7 | ||
|
|
||
| - uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: vrt-report-wp${{ matrix.wp.input }}${{ matrix.multisite && '-multisite' || '' }} | ||
| path: | | ||
| playwright-report/ | ||
| test-results/ | ||
| retention-days: 7 | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -69,6 +69,39 @@ jobs: | |||||
| wp-versions: '["latest", "6.4"]' | ||||||
| ``` | ||||||
|
|
||||||
| ### `reusable-wp-visual-regression.yml` | ||||||
|
|
||||||
| Playwright-based visual regression testing for WordPress. Captures screenshots and compares them against | ||||||
| committed baselines using Playwright's built-in `toHaveScreenshot()` API. | ||||||
|
|
||||||
| Caller repos must include a `.wp-env.json` in their root. The consuming repo's `playwright.config.ts` should | ||||||
| read the `VRT_THRESHOLD`, `VRT_VIEWPORTS`, and `VRT_COLOR_SCHEMES` environment variables to configure test | ||||||
| behavior. Baseline screenshots are stored in the repo (consider Git LFS for large sets). | ||||||
|
|
||||||
| | Input | Type | Default | Description | | ||||||
| |-------|------|---------|-------------| | ||||||
| | `node-version` | string | `"22"` | Node.js version | | ||||||
| | `wp-versions` | string (JSON) | `["latest"]` | WP versions (`"latest"`, `"6.7"`) | | ||||||
| | `multisite` | string | `"none"` | `"none"`, `"both"`, or `"only"` | | ||||||
| | `mailpit` | boolean | `false` | Run Mailpit mail catcher (SMTP `:1025`, API `:8025`) | | ||||||
| | `update-snapshots` | boolean | `false` | Regenerate baseline screenshots | | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default value of
Suggested change
|
||||||
| | `threshold` | string | `"0.2"` | Pixel diff tolerance (`maxDiffPixelRatio`) | | ||||||
| | `viewports` | string (JSON) | `["desktop", "mobile"]` | Viewport presets | | ||||||
| | `color-schemes` | string (JSON) | `["light"]` | Color scheme presets | | ||||||
|
|
||||||
| To accept a visual change, update the baseline by re-running the workflow with `update-snapshots: true`, then | ||||||
| download and commit the updated snapshots from the workflow artifacts. | ||||||
|
|
||||||
| ```yaml | ||||||
| jobs: | ||||||
| visual-regression: | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to the repository style guide, action versions should be pinned to the major version (e.g.,
Suggested change
|
||||||
| uses: apermo/reusable-workflows/.github/workflows/reusable-wp-visual-regression.yml@main | ||||||
| with: | ||||||
| wp-versions: '["latest"]' | ||||||
| viewports: '["desktop", "mobile"]' | ||||||
| color-schemes: '["light", "dark"]' | ||||||
| ``` | ||||||
|
|
||||||
| ### `reusable-ci.yml` | ||||||
|
|
||||||
| PHP CI pipeline with configurable test matrix, PHPStan, and PHPCS. | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow file
reusable-wp-visual-regression.ymlis documented and added to the changelog, but the file itself is missing from the pull request. Please ensure the new workflow file is included in the commit.