Skip to content

Add - Themegrill QA Setup for E2E Testing - #1662

Merged
iamprazol merged 22 commits into
pre-developfrom
add/themegrill-qa
Sep 7, 2026
Merged

Add - Themegrill QA Setup for E2E Testing#1662
iamprazol merged 22 commits into
pre-developfrom
add/themegrill-qa

Conversation

@iamprazol

Copy link
Copy Markdown
Contributor

All Submissions:

Changes proposed in this Pull Request:

Adds a Playwright E2E suite. The plugin had no browser-level tests, so nothing
guarded the flows a release actually breaks.

19 @fresh tests, all passing locally:

  • Submission end to end — a visitor submits a published form anonymously
    and the entry is verified on the Entries screen, values included. This is the
    flow the product exists for and had no coverage at all.
  • Regression guards for every free-testable change between 3.4.8 and 3.6.0,
    each traced to its changelog entry in the spec's @source: the Style
    Customizer revamp (3.6.0), the CAPTCHA language reset, the repeater control
    Pro gate, the field-settings double-click, the Payments rename and System
    Info addons list (3.5.3), plus the conditional-logic upsell and free
    Analytics export/print (3.5.0).
  • Smoke coverage — admin screens and the front end render with no PHP
    error, settings persist across a reload, forms can be created from a template.

Also adds the .themegrill-qa/ QA config (suite manifest with area_paths,
ingested docs index, knowledge file) and a qa-suite.yml CI workflow.

No product code is touched. The only changes to existing files are
package.json / package-lock.json (adds @playwright/test and dotenv as
devDependencies), .gitignore, and .distignore.

How to test the changes in this Pull Request:

  1. npm install --legacy-peer-deps && npx playwright install chromium
    (--legacy-peer-deps is required — this repo has a real peer conflict, see a33051d66).
  2. Create .themegrill-qa/.env.local with TGQA_BASE_URL, TGQA_ADMIN_USER,
    TGQA_ADMIN_PASS pointing at a site with Everest Forms active.
  3. npm run test:e2e -- --grep @fresh — expect 19 passed.

Types of changes:

  • Enhancement (modification of the currently available functionality)

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you successfully ran tests with your changes locally?
  • Have you updated the documentation accordingly?

tg-autopilot and others added 19 commits September 2, 2026 16:52
composer.json declares '>=5.6.20' (an ancient, unmaintained floor), but
the real composer.lock needs 8.2+ (phpspec/prophecy, webmozart/assert
both require it). Confirmed for real: composer install failed outright
on the previous 7.4 default.
@ajna/pagination@1.4.19 peer-requires react-scripts@5.0.1 -> old
TypeScript, but this project pins typescript@5.9.3 -- a genuine
conflict confirmed via npm ERESOLVE, not a build-config issue.
--legacy-peer-deps is a pragmatic workaround scoped to this repo only
(via the install-command override), not a change to the reusable
workflow or any other repo. Does not fix the underlying conflict --
that still needs this repo's own team (drop/replace @ajna/pagination,
or reconcile the TypeScript version).
npm run build runs this repos own fully self-contained release script
(its own npm install, composer install, JS build, and rsync+zip). Our
external composer-install and custom rsync+zip wrapper were redundant
work duplicating it, and never the actual point of failure -- the real
failing composer call lives inside the script itself, fixed separately
in a PR to bin/build-zip.sh.
composer.lock has dev-only packages (phpunit and friends) locked to
versions requiring old PHP, while the production dependencies need a
newer PHP -- no single installed PHP version satisfies both at once.
Composer validates the whole lock file's platform requirements up
front regardless of which packages get installed, so this script's
build failed outright in CI on any modern PHP version.

--ignore-platform-reqs skips that validation. Safe here: this script
never actually runs the dev-only tools it temporarily installs (no
phpunit execution happens before the --no-dev cleanup pass strips
them back out), it only needs them present long enough to satisfy
whatever step expects vendor/ to exist.
Verified working: install-command needs npm ci --legacy-peer-deps (not
a no-op -- cross-env must be resolvable before npm run build can even
start), and install-command values must never contain embedded double
quotes (breaks the reusable workflow's own shell test, confirmed for
real). composer-install: false and build-command: npm run build are
correct as-is, matching bin/build-zip.sh's own self-contained
packaging.
…omposer-platform-reqs

fix: bin/build-zip.sh composer install --ignore-platform-reqs
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

QA suite — passed ✅

All 11 checks passed.

11 passed · 0 failed · 0 skipped · 1 flaky · 318s

⚠️ 1 test passed only on retry

A flaky suite erodes trust faster than a failing one — these are not green.

Test Spec Retries
a colour preset chosen in the panel reaches the rendered form @fresh @style-customizer tests/e2e/specs/style-customizer/color-preset-reaches-front-end.spec.ts:49 1

See it for yourself

Download the full report (qa-suite-everest-forms-1662.zip). Unzip it and open qa-report.html in any browser — it shows each failure with screenshots of the page at the moment it broke, and what the run did and did not check.

Replaying a failure step by step (developers)

The archive also carries a Playwright trace — every click, the page at each step, network and console. From the unzipped folder:

npx playwright show-report playwright-report

It needs that command rather than opening the file directly: a trace viewer cannot start from a file:// page.

Automated check — no AI involved. It runs the tests in this branch.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

It introduces CI/runtime incompatibilities (Playwright requires Node >=20 while existing CI still uses Node 12) and includes a couple of correctness/consistency issues (test cleanup URL param handling, lockfile version mismatch).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces a Playwright-based end-to-end (E2E) test suite for Everest Forms, plus ThemeGrill QA suite metadata and CI wiring, to add browser-level regression coverage for critical user flows and key regressions between 3.4.8–3.6.0 without changing production plugin code.

Changes:

  • Adds a new Playwright E2E suite (tests/e2e/) with fixtures, auth setup, and 19 @fresh specs covering core flows and targeted regressions.
  • Adds ThemeGrill QA suite configuration and ingested docs/knowledge index under .themegrill-qa/.
  • Updates CI/workflows and build scripts to support running the suite and producing testable ZIPs; adds @playwright/test and dotenv devDependencies.
File summaries
File Description
tests/e2e/tsconfig.json TypeScript config for the E2E suite.
tests/e2e/specs/submission/entry-end-to-end.spec.ts Critical “visitor submission persists to Entries” end-to-end coverage.
tests/e2e/specs/style-customizer/style-customizer-v2.spec.ts Guards Style Customizer V2 panel mounting/structure.
tests/e2e/specs/style-customizer/color-preset-reaches-front-end.spec.ts Verifies a saved preset affects frontend computed styles.
tests/e2e/specs/settings/validation-message-persists.spec.ts Asserts settings persistence across save + reload.
tests/e2e/specs/settings/captcha-language-persists.spec.ts Regression guard for CAPTCHA language persistence.
tests/e2e/specs/forms/create-form-from-template.spec.ts Template picker + builder-open regression coverage.
tests/e2e/specs/builder/pro-gated-controls.spec.ts Guards free-vs-pro gated builder controls behavior.
tests/e2e/specs/builder/field-option-groups.spec.ts Regression guard for option group toggle single-click behavior.
tests/e2e/specs/admin/menus-and-pages.spec.ts Admin menu/analytics/system-info surface regression checks.
tests/e2e/specs/activation/admin-screens-render-clean.spec.ts Ensures admin pages and frontend render without PHP errors.
tests/e2e/README.md Suite documentation, conventions, and gaps.
tests/e2e/playwright.config.ts Playwright runner config (serial execution, reporters, projects).
tests/e2e/fixtures/published-form.ts Fixture to publish a real page hosting a form for anonymous visitor tests.
tests/e2e/fixtures/form.ts Shared per-spec-file form fixture created via template picker.
tests/e2e/env.ts Env resolution/precedence and dotenv loading for suite configuration.
tests/e2e/auth.setup.ts Setup project that logs in once and persists storage state.
tests/e2e/.gitignore Ignores E2E auth state and env artifacts under tests/e2e.
package.json Adds Playwright test script and devDependencies (@playwright/test, dotenv).
package-lock.json Locks Playwright/dotenv dependencies (and updates lock metadata).
bin/build-zip.sh Adjusts Composer install flags for build ZIP script.
.themegrill-qa/suite.json ThemeGrill QA suite manifest (tiers, areas, runner command).
.themegrill-qa/knowledge.md Draft QA knowledge base used to justify/organize regression guards.
.themegrill-qa/docs/uncategorised.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/troubleshooting.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/translation.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/tools.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/page-builder-compatibility.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/integrations.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/global-settings.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/getting-started.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/getting-started-with-form.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/developers-doc.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/design.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/anti-spam-and-security.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs/account-management.md Ingested docs section content (reference/intent source).
.themegrill-qa/docs-index.json Index of ingested documentation sections and outcomes.
.themegrill-qa/.docs-cache/_wp-json_wp_v2_doc_category_per_page_100__fields_id_name_slug_count_parent.txt Cached docs ingest API response.
.themegrill-qa/.docs-cache/_wp-json_wp_v2_docs_per_page_100_page_1__fields_id_slug_link_title_content_doc_category.txt Cached docs ingest API response.
.themegrill-qa/.docs-cache/_wp-json_wp_v2_docs_per_page_100_page_2__fields_id_slug_link_title_content_doc_category.txt Cached docs ingest API response.
.gitignore Ignores local QA env and Playwright artifacts at repo root.
.github/workflows/qa-suite.yml Adds CI workflow to run QA suite via ThemeGrill reusable workflow.
.github/workflows/pr-build-zip.yml Updates ZIP build workflow wiring/notes.
.github/workflows/copilot-review-on-comment.yml Adjusts reusable workflow source and adds PR-open trigger.
.distignore Excludes Playwright reports/results from build artifacts.
Review details
  • Files reviewed: 51/56 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread package.json
Comment thread tests/e2e/auth.setup.ts Outdated
Comment thread tests/e2e/specs/forms/create-form-from-template.spec.ts
…sing

Adds a @fresh guard for the 3.6.1 fix "Query parameters in external redirect
URLs were HTML-encoded, causing incorrect values" (e265d5e).

The spec asserts on the *second* query parameter, which is the minimum
meaningful case: esc_url() encoded "&" as "&", the "#" then opened a
fragment, and every parameter after the first fell out of the query silently.
A single-parameter redirect passes with the bug present.

Proved both ways — with esc_url_raw() restored to esc_url() the spec fails on
a landed URL of "?evfqa=<stamp>#38;second=kept", and passes on the fix.

Also reworks auth.setup.ts to report why login failed rather than guess. It now
distinguishes a rejected login (reads #login_error), a PHP fatal in admin
bootstrap, and an unexplained missing admin bar (reports landed URL and body
prefix). The previous message offered "wrong credentials, or the site is not
reachable" for all three, which is unactionable on CI — plugins load on
wp-login.php but admin-only hooks do not, so an admin-side fatal presents
exactly like a bad password.

Documents four things that each cost a debugging cycle: networkidle is not a
save signal in the builder, smart tags are not processed in the confirmation
success message, the external-URL setting strips braces on save, and the
Country smart-tag fix is consequently not reachable from any free surface.

Suite: 20 @fresh tests, all passing against 3.6.1.
The diagnostic added in 8e687fe read `#login_error` with `innerText()`, which
auto-waits for the element to exist. When there is no login error — the
successful path and the PHP-fatal path both — that burned the full
actionability timeout (~30s) before the catch swallowed it, leaving too little
of the test budget for the assertion it was added to serve. CI reported
"Test timeout of 45000ms exceeded" in authenticate, naming where the test
stopped rather than the cause.

It never appeared locally because storedStateStillWorks() finds a cached
.auth/admin.json and returns before the login block. CI has no cache, so only
CI ever took the path. Reproduced locally by deleting tests/e2e/.auth: cold
authenticate went 1.0m and failing against a healthy site, and 1.2s passing
with count() guarding the read.

Audited every other innerText/textContent/getAttribute call in the suite; all
are guarded by a count() or a preceding assertion. Documents the trap, and that
a local run must clear tests/e2e/.auth to exercise what CI exercises.

Suite: 20 @fresh tests, all passing from a cold start.
Node/engines: @playwright/test 1.63 declares `engines.node >= 20`, but
package.json still claimed `>=8.9.3` and evf-PR-test.yml installed Node 12.
Declare the real minimum (node >=20, npm >=8) and bump that workflow to
Node 20.x, matching pr-build-zip.yml. Note npm 6 only WARNs on an engine
mismatch, so this was not failing installs -- engines was simply inaccurate
and CI ran a Node the project no longer supports. Playwright is not pinned
down instead, since that would mean dropping the suite, and engine-strict is
deliberately not set so contributors on older Node get a warning rather than
a hard failure.

Template spec cleanup: the URL assertion accepts (form_id|id) but cleanup
read only form_id, so a redirect carrying `id=` skipped teardown and leaked
the created form. Read both, and fix the failure message which still named
only form_id.

auth.setup.ts: give `context` an explicit BrowserContext | undefined instead
of relying on inference. Not a type error -- evolving-any infers it from the
assignment and tsc 5.9 passes under --strict --noImplicitAny -- but the
explicit type is clearer and matches the inline import() style used above.

package-lock.json: version said 3.6.0 while package.json said 3.6.1; the
3.6.1 bump never regenerated the lock. No package versions change.
@iamprazol
iamprazol merged commit 59d0006 into pre-develop Sep 7, 2026
1 of 4 checks passed
@iamprazol
iamprazol deleted the add/themegrill-qa branch September 7, 2026 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants