Skip to content

ci(e2e): run the 9 cypress specs that existed but were never invoked#1280

Merged
superdav42 merged 4 commits into
mainfrom
chore/e2e-add-unrun-specs
May 26, 2026
Merged

ci(e2e): run the 9 cypress specs that existed but were never invoked#1280
superdav42 merged 4 commits into
mainfrom
chore/e2e-add-unrun-specs

Conversation

@superdav42
Copy link
Copy Markdown
Collaborator

@superdav42 superdav42 commented May 26, 2026

Summary

The .github/workflows/e2e.yml workflow listed only 6 of the 16 spec files in tests/e2e/cypress/integration/. The other 10 were committed, syntactically valid, and well-written — but never executed in CI, so any regression they guarded against could slip through unnoticed.

This change adds 9 of those 10 specs to the workflow. The 10th (installation.spec.js) is intentionally excluded because it has no assertions — see "Excluded spec" below.

Audit of all 16 specs

Spec Was in CI? Now in CI? Group Notes
000-setup.spec.js Setup unchanged
010-manual-checkout-flow.spec.js Checkout unchanged
011-password-reset-subsite-domain.spec.js Regression & UI regression guard for PR #1169
020-free-trial-flow.spec.js Checkout unchanged
030-modal-form-error-handling.spec.js Regression & UI AJAX 500 / bad JSON / network failure handling
030-stripe-checkout-flow.spec.js ✅ (gated) Stripe unchanged
035-paypal-checkout-flow.spec.js ✅ (gated) PayPal (new) needs PAYPAL_SANDBOX_* secrets
040-stripe-renewal-flow.spec.js ✅ (gated) Stripe unchanged
050-password-strength-enforcement.spec.js Regression & UI Strong / Medium / Super-Strong via zxcvbn
060-sso-cross-domain.spec.js SSO mapped domain + auto-auth
065-sso-redirect-loop.spec.js SSO grouped with 060 in this change
066-sso-bootstrap-race.spec.js Regression & UI regression guard for PR #1185
installation.spec.js see "Excluded spec" below
login.spec.js Sanity UI login + API login + logout
mail.spec.js Sanity Mailpit API sanity check
wizard.spec.js Wizard drives the actual Setup Wizard UI

Why wizard.spec.js matters specifically

000-setup.spec.js bypasses the Setup Wizard UI entirely — it calls the installer directly via Core_Installer::_install_database_tables() and flips NETWORK_OPTION_SETUP_FINISHED, then uses fixture scripts to configure the test product, checkout form, gateway, and email settings.

The path actually exercised by a real user — Setup_Wizard_Admin_Page::handle_save_settingsSettings::save_settingsField::set_valuevalidate_textarea_field — was therefore never exercised in CI. That's exactly the path that produces the addslashes() / TypeError fatal when a textarea field receives a non-string value (e.g. a previously-corrupted DB value falling through as $existing_value).

Running wizard.spec.js now covers the wizard form integration path. A unit-level guard for the validator itself is in branch fix/textarea-array-coercion.

Step organisation

After the existing "Run Setup Test (Must Run First)" step, the workflow now runs:

  1. Sanity Testslogin, mail (smoke)
  2. Wizard Testwizard
  3. Regression & UI Tests011, 030-modal-form-error-handling, 050, 066
  4. Checkout Tests010, 020 (existing, unchanged)
  5. SSO Tests060 (new), 065 (was: only 065)
  6. Stripe Tests030-stripe-checkout-flow, 040 (existing, gated)
  7. PayPal Tests035 (new, gated on PAYPAL_SANDBOX_*)

All new groups follow the existing pattern: set +e + per-spec loop + aggregated failure count + final exit 1 if any failed, so a single flake doesn't mask other failures in the same group.

PayPal gating

The PayPal step mirrors the Stripe gating exactly: if PAYPAL_SANDBOX_CLIENT_SECRET is empty (which is the case for fork PRs, and currently also for upstream because the secrets are not configured yet), the step prints a diagnostic message and exits 0.

gh secret list --repo Ultimate-Multisite/ultimate-multisite confirms PAYPAL_SANDBOX_* are not yet present. The PayPal tests will skip until they are added; Stripe continues to run on push to main.

Excluded spec

tests/e2e/cypress/integration/installation.spec.js is not added to CI:

describe("Plugin", () => {
  beforeEach(() => {
    cy.loginByApi(Cypress.env("admin").username, Cypress.env("admin").password);
  });

  it("Should show an error message that the plugin needs to be network activated", () => {
    cy.visit("/wp-admin/");
  });
});

The body is a single cy.visit("/wp-admin/") with no assertions. Its it() title claims to check an error message that never gets verified. Adding it to CI would consume runtime without testing anything. Recommend deleting the file in a follow-up; not removed in this PR to keep the change CI-only.

Verification performed

Check Result
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/e2e.yml'))" ✅ valid YAML
node --check <spec> for each of the 9 added specs ✅ all parse
Fixture file existence: setup-password-reset-subsite.php, setup-sso-bootstrap-race.php, setup-sso-test.php, set-password-strength.php, setup-paypal-gateway.php ✅ all present
Inventory grep: specs referenced in workflow vs specs in repo 15/16 (only installation.spec.js excluded, intentionally)
Existing CI step pattern matched (set +e + per-spec loop + aggregated exit)

What is not verified

Local Cypress execution was not attempted for this change. Each matrix variant requires a fresh npm run env:start:test (Docker image download + WP install + plugin activation), which takes longer than the CI run that gates this merge. Running it locally would also use a different PHP version and OS than the matrix in CI. CI is the canonical verification surface for this change — please review the CI run on this PR.

If any spec fails in CI, the per-spec loop will report exactly which one(s); the existing Dump container logs on setup failure step will also catch wp-env startup issues. I'll iterate as needed.

Risk

  • Test runtime: the matrix (php: 8.1, 8.2) × the new specs adds runtime. Per-spec cypress run calls each pay the cypress-startup cost, so total runtime grows by roughly the per-spec count, not by the actual test work. If the 45-minute timeout-minutes becomes tight, the obvious next step is to consolidate into fewer cypress run invocations (single --spec glob).
  • Test interaction: wizard.spec.js clears NETWORK_OPTION_SETUP_FINISHED and re-marks it at the end. It runs after 000-setup and before the regression / checkout groups; the wizard's "Default Content" step is designed to skip already-created items, so it should not conflict with the test product 000-setup created. If it does conflict, the failure will surface in 010-manual-checkout-flow.spec.js and we can reorder.
  • No behaviour change to any test spec or plugin code — workflow-only.

Follow-ups (not in this PR)

  • Delete tests/e2e/cypress/integration/installation.spec.js (or add real assertions to it).
  • Consider adding a CI step (or a lint) that fails when a *.spec.js exists under tests/e2e/cypress/integration/ but isn't referenced in e2e.yml — would have caught this gap automatically.

Summary by CodeRabbit

  • Tests
    • Enhanced CI/CD pipeline with expanded automated test coverage including sanity checks, wizard validation, regression testing, authentication flows, and payment processing verification.
    • Implemented comprehensive test failure detection to ensure improved code quality and release reliability.

Review Change Stack

The e2e workflow listed only 6 of the 16 spec files in
tests/e2e/cypress/integration/. The other 10 were committed and
syntactically valid but never executed in CI, so any regression they
guarded against could slip through unnoticed.

Audit findings (16 specs total):

  Already in CI (6, unchanged):
    - 000-setup.spec.js
    - 010-manual-checkout-flow.spec.js
    - 020-free-trial-flow.spec.js
    - 030-stripe-checkout-flow.spec.js (gated, STRIPE_TEST_SK_KEY)
    - 040-stripe-renewal-flow.spec.js (gated, STRIPE_TEST_SK_KEY)
    - 065-sso-redirect-loop.spec.js

  Added to CI in this change (9):
    - login.spec.js                                (sanity)
    - mail.spec.js                                 (sanity)
    - wizard.spec.js                               (drives Setup Wizard UI)
    - 011-password-reset-subsite-domain.spec.js    (regression: PR #1169)
    - 030-modal-form-error-handling.spec.js        (UI: AJAX error handling)
    - 050-password-strength-enforcement.spec.js    (UI: zxcvbn scoring)
    - 060-sso-cross-domain.spec.js                 (SSO: domain mapping)
    - 066-sso-bootstrap-race.spec.js               (regression: PR #1185)
    - 035-paypal-checkout-flow.spec.js             (gated, new
                                                    PAYPAL_SANDBOX_*)

  Intentionally excluded (1):
    - installation.spec.js — single ‘cy.visit(/wp-admin/)’ call with
      no assertions; doesn’t actually test anything. Recommend deletion
      in a follow-up; not removed here to keep this change ci-only.

Why wizard.spec.js matters specifically: 000-setup.spec.js bypasses
the Setup Wizard UI by calling the installer + setup-finished flag
directly. The path Setup_Wizard_Admin_Page::handle_save_settings ->
Settings::save_settings -> Field::set_value -> validate_textarea_field
was therefore never exercised in CI. The recent
fix/textarea-array-coercion fix added unit-test coverage for the
validator itself; running wizard.spec.js now covers the integration
path.

Step organisation (after the existing ‘Run Setup Test’):

  1. Sanity Tests       — login, mail            (smoke)
  2. Wizard Test        — wizard
  3. Regression & UI    — 011, 030, 050, 066
  4. Checkout Tests     — 010, 020 (existing)
  5. SSO Tests          — 060 (new), 065         (was: only 065)
  6. Stripe Tests       — 030, 040 (existing, gated)
  7. PayPal Tests       — 035 (new, gated on PAYPAL_SANDBOX_*)

All new groups follow the existing pattern: ‘set +e’ + per-spec loop +
aggregated failure count + final exit 1 if any failed, so a single
flake doesn’t mask other failures.

PayPal step mirrors the Stripe gating: if PAYPAL_SANDBOX_CLIENT_SECRET
is unavailable (typical for fork PRs) the step prints the same
diagnostic message Stripe uses and exits 0. The PAYPAL_SANDBOX_* repo
secrets are not currently configured upstream, so PayPal will skip
until they are added; Stripe continues to run.

Verification performed in this change:
  - YAML parse: python3 -c 'import yaml; yaml.safe_load(open(path))' OK
  - Per-spec node --check on all 9 added specs               OK
  - All referenced fixture .php files exist in tests/e2e/cypress/fixtures
  - Inventory diff: workflow now references 15/16 specs

Local Cypress execution is not attempted in this commit because each
matrix variant requires a fresh wp-env (Docker download + WP install
+ plugin activation + multi-spec run) and would take longer than the
CI run that gates the merge. CI is the canonical verification surface
for this change.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a3cbd18-8e2a-43a4-9438-23c9a7e82f42

📥 Commits

Reviewing files that changed from the base of the PR and between 31736aa and caf596d.

📒 Files selected for processing (1)
  • .github/workflows/e2e.yml

📝 Walkthrough

Walkthrough

The PR expands the E2E Cypress test pipeline by adding six new test execution steps organized in two sequential phases: foundation tests (sanity, wizard UI, post-wizard cleanup) that establish expected application state, followed by extended test coverage (regression/UI, SSO, and conditional PayPal tests) that all use consistent failure-aggregation patterns via Cypress exit codes.

Changes

E2E Cypress Test Pipeline Expansion

Layer / File(s) Summary
Foundation Test Groups (Sanity, Wizard, Cleanup)
.github/workflows/e2e.yml
Adds batch execution for sanity checks (login and mail specs with set +e and exit-code tallying), setup-wizard UI spec, and post-wizard cleanup via WP fixtures to disable the custom login page and restore session expectations.
Extended Test Coverage (Regression, SSO, PayPal)
.github/workflows/e2e.yml
Adds batch execution for regression/UI specs (looped with failure aggregation), grouped SSO specs (cross-domain and redirect-loop looped with exit-code tallying), and conditional PayPal tests that skip when sandbox secrets are absent or run the checkout spec with credentials injected via Cypress --env.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as E2E Workflow
  participant Sanity as Sanity Tests
  participant Wizard as Wizard UI Test
  participant Cleanup as Cleanup Fixtures
  participant Regression as Regression Tests
  participant SSO as SSO Tests
  participant PayPal as PayPal Tests
  
  Workflow->>Sanity: Run login + mail specs (set +e)
  activate Sanity
  Sanity-->>Workflow: aggregate exit code, fail if any spec fails
  deactivate Sanity
  
  Workflow->>Wizard: Run wizard UI spec
  activate Wizard
  Wizard-->>Workflow: exit code
  deactivate Wizard
  
  Workflow->>Cleanup: Run WP eval-file fixtures
  activate Cleanup
  Cleanup-->>Cleanup: Disable custom login page
  Cleanup-->>Workflow: exit code
  deactivate Cleanup
  
  Workflow->>Regression: Loop multiple regression/UI specs
  activate Regression
  Regression->>Regression: Tally Cypress exit codes
  Regression-->>Workflow: exit non-zero if any fail
  deactivate Regression
  
  Workflow->>SSO: Loop cross-domain + redirect-loop specs
  activate SSO
  SSO->>SSO: Aggregate Cypress exit codes
  SSO-->>Workflow: exit non-zero if any fail
  deactivate SSO
  
  Workflow->>PayPal: Check PAYPAL_SANDBOX_CLIENT_SECRET exists
  alt Secrets Present
    PayPal->>PayPal: Inject sandbox credentials via --env
    PayPal->>PayPal: Run PayPal checkout spec
    PayPal-->>Workflow: exit non-zero if spec fails
  else Secrets Missing
    PayPal-->>Workflow: exit 0 (skip)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hopping through workflows with a bound,
Six new test steps spinning 'round and 'round,
From sanity checks to PayPal's embrace,
Each exit code tracked with measured grace,
The CI pipeline learns to speak!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding previously-committed but never-executed Cypress specs to the e2e workflow, matching the core objective of invoking 9 specs that existed but were not run.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/e2e-add-unrun-specs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e.yml:
- Around line 437-452: The conditional that gates PayPal tests only checks
PAYPAL_SANDBOX_CLIENT_SECRET; change the if-condition to test both
PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET (e.g., test -z
"$PAYPAL_SANDBOX_CLIENT_ID" || -z "$PAYPAL_SANDBOX_CLIENT_SECRET" or a combined
-z check) so the job skips when either secret is missing, and update the echo
messages inside that block to mention both PAYPAL_SANDBOX_CLIENT_ID and
PAYPAL_SANDBOX_CLIENT_SECRET to reflect the new gating logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ce75ec2a-1d6d-4f67-8384-e7eb37cbeb4e

📥 Commits

Reviewing files that changed from the base of the PR and between 5064889 and 31736aa.

📒 Files selected for processing (3)
  • .github/workflows/e2e.yml
  • TODO.md
  • todo/PLANS.md

Comment thread .github/workflows/e2e.yml
Comment on lines +437 to +452
if [ -z "$PAYPAL_SANDBOX_CLIENT_SECRET" ]; then
echo "⏭️ Skipping PayPal tests: PAYPAL_SANDBOX_CLIENT_SECRET not available in this run."
echo ""
echo " The repo secrets PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET"
echo " must be configured for these tests to run. GitHub Actions does NOT expose"
echo " secrets to workflows triggered by pull_request events from forked"
echo " repositories — this is a security feature, not a misconfiguration."
echo ""
echo " PayPal tests will run automatically when:"
echo " • this branch is merged to main (push event), or"
echo " • the PR is opened from a branch in the upstream Ultimate-Multisite repo"
echo " AND the PAYPAL_SANDBOX_* secrets have been configured at the repo level."
echo ""
echo " To verify locally, run: gh secret list --repo Ultimate-Multisite/ultimate-multisite"
exit 0
fi
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/e2e.yml"
rg -n 'if \[ -z "\$PAYPAL_SANDBOX_CLIENT_ID" \] \|\| \[ -z "\$PAYPAL_SANDBOX_CLIENT_SECRET" \ ]; then|if \[ -z "\$PAYPAL_SANDBOX_CLIENT_SECRET" \ ]; then' "$FILE"

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/e2e.yml"

# Show the exact gate block around the referenced line range
nl -ba "$FILE" | sed -n '420,470p'

# Find all occurrences of PayPal secret variables
rg -n 'PAYPAL_SANDBOX_CLIENT_(ID|SECRET)' "$FILE" || true

# Look for the specific conditional check patterns (simple, no regex escapes)
rg -n 'if \[ -z "\$PAYPAL_SANDBOX_CLIENT_' "$FILE" || true

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 124


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/e2e.yml"

echo "=== lines 420-470 (with numbers) ==="
awk 'NR>=420 && NR<=470 {printf "%d\t%s\n", NR, $0}' "$FILE"

echo
echo "=== occurrences of both secret names ==="
rg -n 'PAYPAL_SANDBOX_CLIENT_(ID|SECRET)' "$FILE" || true

echo
echo "=== occurrences of the specific skip gate (secret missing) ==="
rg -n 'Skipping PayPal tests|PAYPAL_SANDBOX_CLIENT_SECRET not available|PAYPAL_SANDBOX_CLIENT_ID.*not available|if \[ -z "\$PAYPAL_SANDBOX_CLIENT_' "$FILE" || true

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 3368


Gate PayPal tests on both required secrets

.github/workflows/e2e.yml only skips when PAYPAL_SANDBOX_CLIENT_SECRET is empty; if PAYPAL_SANDBOX_CLIENT_ID is missing (empty) but the secret is present, the job will proceed and fail the tests instead of skipping.

Suggested fix
-          if [ -z "$PAYPAL_SANDBOX_CLIENT_SECRET" ]; then
+          if [ -z "$PAYPAL_SANDBOX_CLIENT_ID" ] || [ -z "$PAYPAL_SANDBOX_CLIENT_SECRET" ]; then
             echo "⏭️  Skipping PayPal tests: PAYPAL_SANDBOX_CLIENT_SECRET not available in this run."

(Also update the skip message to reference both PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET so it matches the new condition.)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ -z "$PAYPAL_SANDBOX_CLIENT_SECRET" ]; then
echo "⏭️ Skipping PayPal tests: PAYPAL_SANDBOX_CLIENT_SECRET not available in this run."
echo ""
echo " The repo secrets PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET"
echo " must be configured for these tests to run. GitHub Actions does NOT expose"
echo " secrets to workflows triggered by pull_request events from forked"
echo " repositories — this is a security feature, not a misconfiguration."
echo ""
echo " PayPal tests will run automatically when:"
echo " • this branch is merged to main (push event), or"
echo " • the PR is opened from a branch in the upstream Ultimate-Multisite repo"
echo " AND the PAYPAL_SANDBOX_* secrets have been configured at the repo level."
echo ""
echo " To verify locally, run: gh secret list --repo Ultimate-Multisite/ultimate-multisite"
exit 0
fi
if [ -z "$PAYPAL_SANDBOX_CLIENT_ID" ] || [ -z "$PAYPAL_SANDBOX_CLIENT_SECRET" ]; then
echo "⏭️ Skipping PayPal tests: PAYPAL_SANDBOX_CLIENT_SECRET not available in this run."
echo ""
echo " The repo secrets PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET"
echo " must be configured for these tests to run. GitHub Actions does NOT expose"
echo " secrets to workflows triggered by pull_request events from forked"
echo " repositories — this is a security feature, not a misconfiguration."
echo ""
echo " PayPal tests will run automatically when:"
echo " • this branch is merged to main (push event), or"
echo " • the PR is opened from a branch in the upstream Ultimate-Multisite repo"
echo " AND the PAYPAL_SANDBOX_* secrets have been configured at the repo level."
echo ""
echo " To verify locally, run: gh secret list --repo Ultimate-Multisite/ultimate-multisite"
exit 0
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yml around lines 437 - 452, The conditional that gates
PayPal tests only checks PAYPAL_SANDBOX_CLIENT_SECRET; change the if-condition
to test both PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET (e.g.,
test -z "$PAYPAL_SANDBOX_CLIENT_ID" || -z "$PAYPAL_SANDBOX_CLIENT_SECRET" or a
combined -z check) so the job skips when either secret is missing, and update
the echo messages inside that block to mention both PAYPAL_SANDBOX_CLIENT_ID and
PAYPAL_SANDBOX_CLIENT_SECRET to reflect the new gating logic.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 26, 2026

Performance Test Results

Performance test results for 9d04976 are in 🛎️!

Note: the numbers in parentheses show the difference to the previous (baseline) test run. Differences below 2% or 0.5 in absolute values are not shown.

URL: /

Run DB Queries Memory Before Template Template WP Total LCP TTFB LCP - TTFB
0 41 37.83 MB 819.00 ms (-38.00 ms / -5% ) 149.00 ms (-4.50 ms / -3% ) 1093.00 ms (+53.50 ms / +5% ) 2058.00 ms (+58.00 ms / +3% ) 1988.00 ms (+62.65 ms / +3% ) 80.35 ms (+5.00 ms / +6% )
1 56 49.13 MB 946.50 ms 145.00 ms (+8.00 ms / +6% ) 1088.00 ms 2086.00 ms 2014.60 ms 70.00 ms

@github-actions
Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

The wizard's Default Content step creates a Login page and points
Ultimate Multisite's custom-login feature at it, which redirects
/wp-login.php -> /login/. The custom page has no #rememberme checkbox,
so cy.loginByForm() fails in every subsequent spec's session-setup hook.

000-setup.spec.js already calls setup-disable-custom-login.php
defensively in its before() hook for the same reason; this CI step
runs the same fixture right after wizard.spec.js so the regression,
checkout, SSO, and gated gateway groups inherit a clean login state.

Observed on PR #1280 cypress matrix run 26456938227 where
030-modal-form-error-handling failed in its session-setup hook with
'Expected to find element: #rememberme, but never found it', cascading
into every subsequent step being skipped.
@superdav42 superdav42 merged commit 5717643 into main May 26, 2026
8 of 11 checks passed
@superdav42
Copy link
Copy Markdown
Collaborator Author

Summary

The .github/workflows/e2e.yml workflow listed only 6 of the 16 spec files in tests/e2e/cypress/integration/. The other 10 were committed, syntactically valid, and well-written — but never executed in CI, so any regression they guarded against could slip through unnoticed.
This change adds 9 of those 10 specs to the workflow. The 10th (installation.spec.js) is intentionally excluded because it has no assertions — see "Excluded spec" below.

Audit of all 16 specs

Spec Was in CI? Now in CI? Group Notes
000-setup.spec.js Setup unchanged
010-manual-checkout-flow.spec.js Checkout unchanged
011-password-reset-subsite-domain.spec.js Regression & UI regression guard for PR #1169
020-free-trial-flow.spec.js Checkout unchanged
030-modal-form-error-handling.spec.js Regression & UI AJAX 500 / bad JSON / network failure handling
030-stripe-checkout-flow.spec.js ✅ (gated) Stripe unchanged
035-paypal-checkout-flow.spec.js ✅ (gated) PayPal (new) needs PAYPAL_SANDBOX_* secrets
040-stripe-renewal-flow.spec.js ✅ (gated) Stripe unchanged
050-password-strength-enforcement.spec.js Regression & UI Strong / Medium / Super-Strong via zxcvbn
060-sso-cross-domain.spec.js SSO mapped domain + auto-auth
065-sso-redirect-loop.spec.js SSO grouped with 060 in this change
066-sso-bootstrap-race.spec.js Regression & UI regression guard for PR #1185
installation.spec.js see "Excluded spec" below
login.spec.js Sanity UI login + API login + logout
mail.spec.js Sanity Mailpit API sanity check
wizard.spec.js Wizard drives the actual Setup Wizard UI

Why wizard.spec.js matters specifically

000-setup.spec.js bypasses the Setup Wizard UI entirely — it calls the installer directly via Core_Installer::_install_database_tables() and flips NETWORK_OPTION_SETUP_FINISHED, then uses fixture scripts to configure the test product, checkout form, gateway, and email settings.
The path actually exercised by a real user — Setup_Wizard_Admin_Page::handle_save_settingsSettings::save_settingsField::set_valuevalidate_textarea_field — was therefore never exercised in CI. That's exactly the path that produces the addslashes() / TypeError fatal when a textarea field receives a non-string value (e.g. a previously-corrupted DB value falling through as $existing_value).
Running wizard.spec.js now covers the wizard form integration path. A unit-level guard for the validator itself is in branch fix/textarea-array-coercion.

Step organisation

After the existing "Run Setup Test (Must Run First)" step, the workflow now runs:

  1. Sanity Testslogin, mail (smoke)
  2. Wizard Testwizard
  3. Regression & UI Tests011, 030-modal-form-error-handling, 050, 066
  4. Checkout Tests010, 020 (existing, unchanged)
  5. SSO Tests060 (new), 065 (was: only 065)
  6. Stripe Tests030-stripe-checkout-flow, 040 (existing, gated)
  7. PayPal Tests035 (new, gated on PAYPAL_SANDBOX_*)
    All new groups follow the existing pattern: set +e + per-spec loop + aggregated failure count + final exit 1 if any failed, so a single flake doesn't mask other failures in the same group.

PayPal gating

The PayPal step mirrors the Stripe gating exactly: if PAYPAL_SANDBOX_CLIENT_SECRET is empty (which is the case for fork PRs, and currently also for upstream because the secrets are not configured yet), the step prints a diagnostic message and exits 0.
gh secret list --repo Ultimate-Multisite/ultimate-multisite confirms PAYPAL_SANDBOX_* are not yet present. The PayPal tests will skip until they are added; Stripe continues to run on push to main.

Excluded spec

tests/e2e/cypress/integration/installation.spec.js is not added to CI:

describe("Plugin", () => {
  beforeEach(() => {
    cy.loginByApi(Cypress.env("admin").username, Cypress.env("admin").password);
  });
  it("Should show an error message that the plugin needs to be network activated", () => {
    cy.visit("/wp-admin/");
  });
});

The body is a single cy.visit("/wp-admin/") with no assertions. Its it() title claims to check an error message that never gets verified. Adding it to CI would consume runtime without testing anything. Recommend deleting the file in a follow-up; not removed in this PR to keep the change CI-only.

Verification performed

Check Result
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/e2e.yml'))" ✅ valid YAML
node --check <spec> for each of the 9 added specs ✅ all parse
Fixture file existence: setup-password-reset-subsite.php, setup-sso-bootstrap-race.php, setup-sso-test.php, set-password-strength.php, setup-paypal-gateway.php ✅ all present
Inventory grep: specs referenced in workflow vs specs in repo 15/16 (only installation.spec.js excluded, intentionally)
Existing CI step pattern matched (set +e + per-spec loop + aggregated exit)

What is not verified

Local Cypress execution was not attempted for this change. Each matrix variant requires a fresh npm run env:start:test (Docker image download + WP install + plugin activation), which takes longer than the CI run that gates this merge. Running it locally would also use a different PHP version and OS than the matrix in CI. CI is the canonical verification surface for this change — please review the CI run on this PR.
If any spec fails in CI, the per-spec loop will report exactly which one(s); the existing Dump container logs on setup failure step will also catch wp-env startup issues. I'll iterate as needed.

Risk

  • Test runtime: the matrix (php: 8.1, 8.2) × the new specs adds runtime. Per-spec cypress run calls each pay the cypress-startup cost, so total runtime grows by roughly the per-spec count, not by the actual test work. If the 45-minute timeout-minutes becomes tight, the obvious next step is to consolidate into fewer cypress run invocations (single --spec glob).
  • Test interaction: wizard.spec.js clears NETWORK_OPTION_SETUP_FINISHED and re-marks it at the end. It runs after 000-setup and before the regression / checkout groups; the wizard's "Default Content" step is designed to skip already-created items, so it should not conflict with the test product 000-setup created. If it does conflict, the failure will surface in 010-manual-checkout-flow.spec.js and we can reorder.
  • No behaviour change to any test spec or plugin code — workflow-only.

Follow-ups (not in this PR)

  • Delete tests/e2e/cypress/integration/installation.spec.js (or add real assertions to it).
  • Consider adding a CI step (or a lint) that fails when a *.spec.js exists under tests/e2e/cypress/integration/ but isn't referenced in e2e.yml — would have caught this gap automatically.


Merged via PR #1280 to main.
Merged by deterministic merge pass (pulse-wrapper.sh).


aidevops.sh v3.19.5 spent 47s on this as a headless bash routine.

@github-actions
Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-feedback-scanned Merged PR already scanned for quality feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant