Skip to content

Multi-agent defaults: 5 built-in agents with per-agent tools, prompts, and suggestions #1173

Multi-agent defaults: 5 built-in agents with per-agent tools, prompts, and suggestions

Multi-agent defaults: 5 built-in agents with per-agent tools, prompts, and suggestions #1173

Workflow file for this run

name: E2E Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true
jobs:
e2e:
name: Playwright E2E (WP ${{ matrix.wp }} shard ${{ matrix.shard }})
runs-on: ubuntu-latest
# Each shard runs ~1/3 of the 13 spec files. 90 min accounts for setup
# overhead (~20 min: npm ci, composer, wp-env start) + worst-case test
# runtime (2 retries at 90 s/test × 3 attempts / 2 workers). The 60-min
# limit was exceeded after the per-test timeout increased from 60 s to
# 90 s in playwright.config.js — setup + test time could exceed 60 min.
timeout-minutes: 90
# WP trunk may fail due to PSR namespace conflicts between our compat
# layer and core's native AI Client SDK (see tests.yml for details).
continue-on-error: ${{ matrix.wp == 'trunk' }}
strategy:
fail-fast: false
matrix:
wp: ['6.9', 'trunk']
# 3 shards split 13 spec files into ~4-5 files each. With the 90-min
# job timeout, each shard has ample headroom even with 2 retries.
shard: [1, 2, 3]
include:
- wp: '6.9'
wp_env_port: '8890'
wp_env_override: ''
# 2 workers on WP 6.9: 3 workers cause resource contention that
# manifests as login and SPA-render timeouts on CI runners.
playwright_workers: '2'
- wp: 'trunk'
wp_env_port: '8890'
wp_env_override: '{"core":"WordPress/WordPress#master"}'
# 2 workers on WP trunk: same resource contention as WP 6.9 —
# 3 workers cause login and SPA-render timeouts on CI runners.
playwright_workers: '2'
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '24'
cache: 'npm'
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, intl, zip
tools: composer:v2
coverage: none
- name: Get Composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v5
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install --prefer-dist --no-progress
- name: Install Node dependencies
run: npm ci
- name: Patch @wordpress/env phpunit constraint
# @wordpress/env's CLI.Dockerfile installs phpunit globally. Composer
# 2.6+ defaults audit.block-insecure to true, which blocks ALL phpunit
# versions (v5–v11) due to security advisories PKSA-5jz8-6tcw-pbk4 and
# PKSA-z3gr-8qht-p93v. COMPOSER_NO_AUDIT=1 only skips post-install
# audit reporting — it does NOT disable block-insecure resolution blocking.
# Fix: prepend 'composer config --global audit.block-insecure false &&'
# to disable the resolver-level block before running the install.
# v10.x uses init-config.js; v11.x renamed it to docker-config.js.
# Remove once @wordpress/env ships a fix upstream.
run: |
node -e "
const fs = require('fs');
const path = require('path');
const base = 'node_modules/@wordpress/env/lib/runtime/docker/';
const candidates = ['init-config.js', 'docker-config.js'];
const before = 'RUN composer global require --dev phpunit/phpunit:\"^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0\"';
const after = 'RUN composer config --global audit.block-insecure false && composer global require --dev phpunit/phpunit:\"^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0\"';
let patched = false;
for (const name of candidates) {
const f = path.resolve(base + name);
if (!fs.existsSync(f)) continue;
let c = fs.readFileSync(f, 'utf8');
if (!c.includes(before)) { console.log(name + ': already patched or pattern changed, skipping'); continue; }
fs.writeFileSync(f, c.replace(before, after));
console.log('Patched ' + f);
patched = true;
}
if (!patched) console.log('No files needed patching');
"
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Build plugin assets
run: npm run build
- name: Override wp-env core version
if: matrix.wp_env_override != ''
env:
WP_ENV_OVERRIDE: ${{ matrix.wp_env_override }}
run: |
node -e "
const fs = require('fs');
const base = JSON.parse(fs.readFileSync('.wp-env.json', 'utf8'));
const override = JSON.parse(process.env.WP_ENV_OVERRIDE);
Object.assign(base, override);
fs.writeFileSync('.wp-env.override.json', JSON.stringify(base, null, 2));
"
- name: Start wp-env
run: npm run wp-env:start
timeout-minutes: 10
env:
WP_ENV_HOME: /tmp/wp-env
- name: Wait for wp-env to be ready
run: |
ready=0
for i in $(seq 1 30); do
if curl -s -o /dev/null -w "%{http_code}" http://localhost:${{ matrix.wp_env_port }}/wp-login.php | grep -q "200"; then
echo "wp-env is ready on port ${{ matrix.wp_env_port }}"
ready=1
break
fi
echo "Waiting for wp-env... attempt $i"
sleep 5
done
if [ "$ready" -ne 1 ]; then
echo "wp-env did not become ready in time on port ${{ matrix.wp_env_port }}" >&2
exit 1
fi
- name: Verify plugin health
run: |
echo "=== Plugin status ==="
npx wp-env run cli wp plugin list --format=table
echo ""
echo "=== Verify plugin is active ==="
npx wp-env run cli wp plugin is-active gratis-ai-agent && echo "Plugin is active" || echo "ERROR: Plugin is NOT active"
echo ""
echo "=== Check admin page loads (HTTP status) ==="
# Log in and fetch the admin page to verify the SPA renders.
# First get a login cookie, then check the plugin page.
LOGIN_COOKIE=$(curl -s -c - -d "log=admin&pwd=password&wp-submit=Log+In" \
"http://localhost:${{ matrix.wp_env_port }}/wp-login.php" | grep wordpress_logged_in | awk '{print $NF}')
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -b "wordpress_logged_in_=$(echo $LOGIN_COOKIE)" \
"http://localhost:${{ matrix.wp_env_port }}/wp-admin/admin.php?page=gratis-ai-agent")
echo "Admin page HTTP status: $STATUS"
echo ""
echo "=== PHP error log (last 30 lines) ==="
npx wp-env run cli cat /var/www/html/wp-content/debug.log 2>/dev/null | tail -30 || echo "(no error log)"
env:
WP_ENV_HOME: /tmp/wp-env
- name: Configure plugin for E2E tests
run: |
# Mark onboarding complete so the main chat UI renders (not the wizard).
# Disable site_builder_mode so the FAB renders instead of the full-screen
# SiteBuilderOverlay (wp-env is a fresh install, which auto-enables it).
npx wp-env run cli wp option update gratis_ai_agent_settings \
'{"onboarding_complete":true,"site_builder_mode":false}' --format=json
# Configure a fake OpenAI key so the /providers endpoint returns at
# least one provider. Without a provider the AdminPageApp renders the
# ConnectorGate instead of the chat layout, breaking all tests that
# look for .gratis-ai-agent-layout or .gratis-ai-agent-chat-panel.
# The key is never used for real API calls — E2E specs mock the
# /stream endpoint — but its non-empty value is enough for the
# SettingsController::handle_providers() to include OpenAI in the
# list returned to the React app.
npx wp-env run cli wp option update gratis_ai_agent_provider_keys \
'{"openai":"sk-test-fake-key-for-e2e"}' --format=json
# Prevent FreshInstallDetector from re-enabling site_builder_mode on
# every page load. The wp-env environment is always a "fresh install"
# (default theme, only sample posts), so isFreshInstall() returns true
# and FloatingWidget::enqueue_widget_assets() re-enables site_builder_mode
# even after we set it to false above. Setting this transient to '0'
# caches the detection result as "not fresh" for 5 minutes.
npx wp-env run cli wp transient set gratis_ai_agent_fresh_install 0 300
# Create a real post so the site is no longer detected as a fresh install
# even after the transient expires (belt-and-suspenders).
npx wp-env run cli wp post create --post_title='E2E Test Post' \
--post_status=publish --post_type=post
# Create the second admin user required by shared-conversations.spec.js.
# Done here (not in test.beforeAll) so WP_ENV_HOME is available and
# wp-env can locate its docker-compose.yml.
npx wp-env run cli wp user create admin2 admin2@example.com \
--role=administrator --user_pass=password2 --send-email=false || true
env:
WP_ENV_HOME: /tmp/wp-env
- name: Run Playwright E2E tests (shard ${{ matrix.shard }}/3)
run: npx playwright test --shard=${{ matrix.shard }}/3
env:
WP_BASE_URL: http://localhost:${{ matrix.wp_env_port }}
WP_ADMIN_USER: admin
WP_ADMIN_PASSWORD: password
CI: true
PLAYWRIGHT_WORKERS: ${{ matrix.playwright_workers }}
- name: Upload Playwright report
uses: actions/upload-artifact@v7
if: always()
with:
# Artifact name includes shard index to avoid name collisions between
# shards of the same WP version.
name: playwright-report-wp${{ matrix.wp }}-shard${{ matrix.shard }}
path: playwright-report/
retention-days: 14
- name: Upload test results
uses: actions/upload-artifact@v7
if: failure()
with:
name: test-results-wp${{ matrix.wp }}-shard${{ matrix.shard }}
path: test-results/
retention-days: 7
- name: Dump PHP error log on failure
if: failure()
run: |
echo "=== PHP debug.log ==="
npx wp-env run cli cat /var/www/html/wp-content/debug.log 2>/dev/null | tail -100 || echo "(no error log)"
env:
WP_ENV_HOME: /tmp/wp-env
- name: Stop wp-env
if: always()
run: npm run wp-env:stop
env:
WP_ENV_HOME: /tmp/wp-env