Skip to content

E2E: add activation smoke tests + license activation test#29

Open
Mwalek wants to merge 4 commits intodevelopfrom
feature/e2e-license-activation-test
Open

E2E: add activation smoke tests + license activation test#29
Mwalek wants to merge 4 commits intodevelopfrom
feature/e2e-license-activation-test

Conversation

@Mwalek
Copy link
Copy Markdown

@Mwalek Mwalek commented Apr 8, 2026

Summary

First-time E2E setup for Dashboard Views using @gravitykit/e2e-bootstrap.

  • Bootstrap-based wp-env / Playwright config (generateWpEnvConfig, createPlaywrightConfig, createGlobalSetup, createGlobalTeardown)
  • Standardized npm scripts (wp-env:start/stop/cli, tests:e2e:setup/run/debug)
  • wp-env:cli targets the dev cli container so the bootstrap's afterStart commands (rewrite, plugin install, license activation) configure the same WP instance Playwright queries — see the bootstrap migration plan, critical lesson Links all don't work #1
  • Activation smoke spec with the four required checks:
    • Plugin activates without fatal PHP errors
    • WordPress admin dashboard loads cleanly
    • Gravity Forms admin page loads
    • Product is listed as active on the GravityKit licenses page
  • CircleCI restructured to add prepare_test_and_build_environment + run_e2e_tests jobs feeding into the existing build_package_release job
  • .env.sample template, .gitignore entries for generated wp-env / playwright artifacts

Test plan

  • Local cold start: npm run tests:e2e:setup → no afterStart errors
  • Local: npm run tests:e2e:run → 4/4 passed
  • CircleCI: prepare_test_and_build_environment passes
  • CircleCI: run_e2e_tests passes (all 4 activation tests)
  • CircleCI: build_package_release still passes

Summary by CodeRabbit

  • Tests
    • Added Playwright E2E suite and smoke tests for activation, dashboard, and license UI; CI captures artifacts and results with retry logic.
  • New Features
    • Integrated Playwright/WordPress E2E tooling and npm scripts for local and CI runs; added sample env variables for plugin mounts and license injection.
  • Chores
    • CI workflow split into prepare → E2E → package steps; updated .gitignore for E2E artifacts and updated packaging flow.

💾 Build file (2103899).

Bootstrap-based E2E setup using @gravitykit/e2e-bootstrap:
- generateWpEnvConfig / createPlaywrightConfig / createGlobalSetup / createGlobalTeardown
- Standardized npm scripts (wp-env:start/stop/cli, tests:e2e:setup/run/debug)
- wp-env:cli targets the dev `cli` container (not `tests-cli`) so the
  bootstrap's afterStart commands configure the same WP instance Playwright
  queries (see Tooling/.claude/e2e-bootstrap-migration.md, critical lesson #1)

Activation smoke spec covers the four required checks:
- Plugin activates without fatal PHP errors (via plugins.php Deactivate link)
- WordPress admin dashboard loads cleanly
- Gravity Forms admin page loads (exercises full plugin init path)
- Product is listed as active on the GravityKit licenses page

CircleCI restructured to add prepare_test_and_build_environment +
run_e2e_tests jobs feeding into the existing build_package_release job,
matching the GravityCharts pattern.

Verified locally: cold-start tests:e2e:setup → tests:e2e:run → 4/4 passed.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

Walkthrough

Restructures CI into prepare → E2E → package jobs; adds Playwright + wp-env E2E setup and tests, new npm/dev dependencies and scripts, .env.sample, and .gitignore updates. CI persists workspace, runs Playwright with retries, and stores artifacts/JUnit results.

Changes

Cohort / File(s) Summary
CI/CD Pipeline
​.circleci/config.yml
Replaces single job with three: prepare_test_and_build_environment (npm auth, multi-key cache, install npm/composer deps, download/unzip releases, generate .env, persist full workspace), run_e2e_tests (attach workspace, run npm run tests:e2e:setup with up to 3 retries, clean /home/circleci/.wp-env between attempts, discover specs, run Playwright, store artifacts & JUnit), and updated build_package_release (attach workspace, set HUSKY: "0", run composer install --no-dev, then grunt/packaging).
Environment & VCS ignores
.env.sample, .gitignore
Adds .env.sample with WP_ENV_PLUGINS, GRAVITY_FORMS_LICENSE_KEY, GRAVITYKIT_LICENSE_KEY and optional tunables; updates .gitignore to ignore .env, vendor_prefixed, and E2E artifacts under tests/E2E/.
Dependencies & Scripts
package.json
Adds @gravitykit/e2e-bootstrap dependency and @playwright/test, @wordpress/env devDeps; adds wp-env:* and E2E scripts (tests:e2e:setup, tests:e2e:run, tests:e2e:debug) and minor prepare script tweak.
Playwright & wp-env setup
tests/E2E/setup/playwright.config.js, tests/E2E/setup/playwright.global.setup.js, tests/E2E/setup/playwright.global.teardown.js, tests/E2E/setup/wp-env.config.js
Adds Playwright config and global setup/teardown delegating to @gravitykit/e2e-bootstrap; adds wp-env.config.js which loads .env and calls generateWpEnvConfig with outputDir and pluginPath, exiting on error.
E2E Tests
tests/E2E/tests/activation.spec.js
Adds activation smoke tests validating plugin activation, absence of fatal-error banner across admin pages, Gravity Forms admin load, and GravityKit licenses UI state; includes a deactivate/reactivate flow that handles browser dialogs.
Test artifacts & CI wiring
tests/E2E/..., tests/E2E/setup/...
Wires Playwright to use the new setup config, ensures CI stores Playwright artifacts and JUnit results, and excludes test artifacts from VCS via .gitignore.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(87, 156, 212, 0.5)
    participant CircleCI
    end
    rect rgba(46, 204, 113, 0.5)
    participant Workspace
    end
    rect rgba(241, 196, 15, 0.5)
    participant Playwright
    end
    rect rgba(155, 89, 182, 0.5)
    participant WP_Env
    end

    CircleCI->>Workspace: prepare_test_and_build_environment\n(create .npmrc, restore caches, install deps, download/unzip releases, generate .env, persist workspace)
    Workspace-->>CircleCI: persisted workspace
    CircleCI->>Workspace: run_e2e_tests (attach workspace)
    loop up to 3 attempts
      Workspace->>WP_Env: npm run tests:e2e:setup (generate wp-env files)
      WP_Env-->>Workspace: wp-env config and environment
      Workspace->>Playwright: run Playwright tests (tests/E2E/setup/playwright.config.js)
      Playwright-->>Workspace: artifacts, junit results
      Workspace->>Workspace: remove /home/circleci/.wp-env (between attempts if failed)
    end
    CircleCI->>Workspace: build_package_release (attach workspace)
    Workspace->>Workspace: composer install --no-dev
    Workspace-->>CircleCI: package artifacts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary changes: adding E2E test infrastructure and activation smoke tests with license activation validation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/e2e-license-activation-test

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.

Copy link
Copy Markdown

@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: 3

🧹 Nitpick comments (3)
package.json (1)

5-7: Move @gravitykit/e2e-bootstrap to devDependencies.

This package is only used in E2E test setup files (tests/E2E/setup/) and has no runtime usage. Keeping it in dependencies increases production installation surface without benefit.

♻️ Proposed fix
-  "dependencies": {
-    "@gravitykit/e2e-bootstrap": "^1.0.0"
-  },
+  "dependencies": {},
   "devDependencies": {
+    "@gravitykit/e2e-bootstrap": "^1.0.0",
     "@playwright/test": "1.56.1",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 5 - 7, Move the package
"@gravitykit/e2e-bootstrap" from the "dependencies" block to the
"devDependencies" block in package.json; update the JSON so
"@gravitykit/e2e-bootstrap": "^1.0.0" appears under devDependencies (not
dependencies) to ensure it's only installed for development/test environments
and not included in production installs.
.circleci/config.yml (2)

61-64: Broad workspace persistence may include sensitive data.

Persisting the entire home directory (/home/circleci/.) includes the .env file with license keys. While the workspace is internal to CircleCI, consider persisting only required paths to minimize exposure surface and reduce workspace size/transfer time.

Suggested more targeted persistence
       - persist_to_workspace:
           root: /home/circleci
           paths:
-            - .
+            - plugin
+            - tooling
+            - .npmrc
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.circleci/config.yml around lines 61 - 64, The current persist_to_workspace
step is persisting the entire home directory (persist_to_workspace with root:
/home/circleci and paths: - .), which can include sensitive files like .env;
update this step to persist only the specific directories or files needed for
downstream jobs (e.g., the repository workspace, build/artifact directories, and
any generated caches) and explicitly exclude secrets (.env, SSH keys, license
files). Replace the broad paths entry with a targeted list (only the exact
folders used later in your workflow) or add an explicit exclusion mechanism, and
ensure downstream jobs reference those specific paths instead of assuming the
whole home directory is available.

22-22: Unused .date file generated.

The .date file is written but not referenced in any cache key or subsequent step. If this was intended for cache busting, it should be included in a cache key checksum; otherwise, this line can be removed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.circleci/config.yml at line 22, The pipeline step that runs "date +%F >
.date" is creating an unused artifact; either remove that run step entirely from
the workflow or make the file serve a purpose by including ".date" in the cache
key/checksum used by the cache step (so it affects cache busting). Locate the
run step that writes ".date" in the CircleCI job and either delete that line or
update the corresponding cache restore/save steps to reference ".date" in their
key/checksum parameters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.circleci/config.yml:
- Around line 96-97: The CircleCI job uses store_test_results with a file path;
change the value under store_test_results (the store_test_results key) to the
directory containing the results (e.g., "tests/E2E/results" or
"tests/E2E/results/") instead of "tests/E2E/results/junit.xml" so CircleCI can
collect all test result files.

In `@tests/E2E/setup/wp-env.config.js`:
- Line 5: Before calling loadEnv(path.resolve(__dirname, '../../../.env')) add
an explicit filesystem check (e.g., using fs.existsSync or fs.stat) to verify
the .env file exists; if it does not, log a clear error instructing the user to
copy .env.sample to .env (include the resolved path) and exit with a non-zero
status instead of allowing loadEnv to throw. Modify the setup in
tests/E2E/setup/wp-env.config.js around the loadEnv call so the existence check
runs first and only calls loadEnv when the file is present.

In `@tests/E2E/tests/activation.spec.js`:
- Around line 43-52: Guard the end-to-end test that checks GravityKit licenses
by skipping it when the license env var is not provided: wrap or modify the test
named "product is listed as active in GravityKit licenses" (the test(...) block
that defines productCard and assertions) to call Playwright's test.skip when
process.env.GRAVITYKIT_LICENSE_KEY (or equivalent GRAVITYKIT_LICENSE_KEY env) is
falsy, so local runs without a license key do not execute the license-specific
navigation and assertions.

---

Nitpick comments:
In @.circleci/config.yml:
- Around line 61-64: The current persist_to_workspace step is persisting the
entire home directory (persist_to_workspace with root: /home/circleci and paths:
- .), which can include sensitive files like .env; update this step to persist
only the specific directories or files needed for downstream jobs (e.g., the
repository workspace, build/artifact directories, and any generated caches) and
explicitly exclude secrets (.env, SSH keys, license files). Replace the broad
paths entry with a targeted list (only the exact folders used later in your
workflow) or add an explicit exclusion mechanism, and ensure downstream jobs
reference those specific paths instead of assuming the whole home directory is
available.
- Line 22: The pipeline step that runs "date +%F > .date" is creating an unused
artifact; either remove that run step entirely from the workflow or make the
file serve a purpose by including ".date" in the cache key/checksum used by the
cache step (so it affects cache busting). Locate the run step that writes
".date" in the CircleCI job and either delete that line or update the
corresponding cache restore/save steps to reference ".date" in their
key/checksum parameters.

In `@package.json`:
- Around line 5-7: Move the package "@gravitykit/e2e-bootstrap" from the
"dependencies" block to the "devDependencies" block in package.json; update the
JSON so "@gravitykit/e2e-bootstrap": "^1.0.0" appears under devDependencies (not
dependencies) to ensure it's only installed for development/test environments
and not included in production installs.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dbe23ec8-7f27-44a3-9de2-abde74506bd9

📥 Commits

Reviewing files that changed from the base of the PR and between 92039ba and 88fd1bd.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • .circleci/config.yml
  • .env.sample
  • .gitignore
  • package.json
  • tests/E2E/setup/playwright.config.js
  • tests/E2E/setup/playwright.global.setup.js
  • tests/E2E/setup/playwright.global.teardown.js
  • tests/E2E/setup/wp-env.config.js
  • tests/E2E/tests/activation.spec.js

Comment thread .circleci/config.yml
Comment on lines +96 to +97
- store_test_results:
path: tests/E2E/results/junit.xml
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

store_test_results expects a directory path, not a file.

CircleCI's store_test_results requires a directory containing test result files, not a direct file path. The current path tests/E2E/results/junit.xml should be changed to the directory.

Proposed fix
       - store_test_results:
-          path: tests/E2E/results/junit.xml
+          path: tests/E2E/results
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.circleci/config.yml around lines 96 - 97, The CircleCI job uses
store_test_results with a file path; change the value under store_test_results
(the store_test_results key) to the directory containing the results (e.g.,
"tests/E2E/results" or "tests/E2E/results/") instead of
"tests/E2E/results/junit.xml" so CircleCI can collect all test result files.

const { generateWpEnvConfig, loadEnv } = require('@gravitykit/e2e-bootstrap');

// Explicit load — INIT_CWD unreliable via npm run on some machines (see Tooling/.claude/e2e-bootstrap-migration.md)
loadEnv(path.resolve(__dirname, '../../../.env'));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add explicit .env existence validation before loading.

Line 5 unconditionally loads .env; on fresh clones this can fail with a non-actionable stack trace. Add a clear precheck and message to copy from .env.sample.

🛠️ Proposed fix
 const path = require('path');
+const fs = require('fs');
 const { generateWpEnvConfig, loadEnv } = require('@gravitykit/e2e-bootstrap');

 // Explicit load — INIT_CWD unreliable via npm run on some machines (see Tooling/.claude/e2e-bootstrap-migration.md)
-loadEnv(path.resolve(__dirname, '../../../.env'));
+const envPath = path.resolve(__dirname, '../../../.env');
+if (!fs.existsSync(envPath)) {
+	console.error('Missing .env file. Copy .env.sample to .env and set required keys.');
+	process.exit(1);
+}
+loadEnv(envPath);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/E2E/setup/wp-env.config.js` at line 5, Before calling
loadEnv(path.resolve(__dirname, '../../../.env')) add an explicit filesystem
check (e.g., using fs.existsSync or fs.stat) to verify the .env file exists; if
it does not, log a clear error instructing the user to copy .env.sample to .env
(include the resolved path) and exit with a non-zero status instead of allowing
loadEnv to throw. Modify the setup in tests/E2E/setup/wp-env.config.js around
the loadEnv call so the existence check runs first and only calls loadEnv when
the file is present.

Comment on lines +43 to +52
test('product is listed as active in GravityKit licenses', async ({ page }) => {
await page.goto('/wp-admin/admin.php?page=gk_licenses&filter=active');

const productCard = page.locator('.sections .grid > div').filter({
has: page.locator('h3', { hasText: 'Dashboard Views' }),
});

await expect(productCard).toBeVisible();
await expect(productCard.locator('button[role="switch"][aria-checked="true"]')).toBeVisible();
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current license-test gating and env-key usage in E2E tests.
rg -n -C3 "GRAVITYKIT_LICENSE_KEY|gk_licenses|test\\.skip" tests/E2E

Repository: GravityKit/Dashboard-Views

Length of output: 626


🏁 Script executed:

# Read the full activation.spec.js file
cat -n tests/E2E/tests/activation.spec.js

Repository: GravityKit/Dashboard-Views

Length of output: 2440


🏁 Script executed:

# Check .env.sample to see default license config
cat -n .env.sample 2>/dev/null || cat -n .env.example 2>/dev/null || echo "No env sample found"

Repository: GravityKit/Dashboard-Views

Length of output: 677


🏁 Script executed:

# Search for any existing skip logic or license checks in E2E tests
rg -n "test\.skip|testInfo\.skip|\.skip\(" tests/E2E --type javascript

Repository: GravityKit/Dashboard-Views

Length of output: 104


🏁 Script executed:

# Search for env variable usage in E2E tests
rg -n "process\.env" tests/E2E --type javascript

Repository: GravityKit/Dashboard-Views

Length of output: 104


🏁 Script executed:

# Search for test setup, hooks, or beforeAll/beforeEach in E2E tests
rg -n "beforeAll|beforeEach|test\.describe|skip" tests/E2E/tests/

Repository: GravityKit/Dashboard-Views

Length of output: 171


🏁 Script executed:

# Search for any other tests that might check license availability
rg -n "gk_licenses" --type js .

Repository: GravityKit/Dashboard-Views

Length of output: 182


🏁 Script executed:

# Check if there's a setup file or config for E2E tests
find tests/E2E -name "*.config.*" -o -name "setup*" -o -name "fixtures*" | head -20

Repository: GravityKit/Dashboard-Views

Length of output: 155


🏁 Script executed:

# Search entire codebase for GRAVITYKIT_LICENSE_KEY to understand how it's used
rg -n "GRAVITYKIT_LICENSE_KEY" --type js .

Repository: GravityKit/Dashboard-Views

Length of output: 52


🏁 Script executed:

# Check playwright config
cat -n tests/E2E/setup/playwright.config.js

Repository: GravityKit/Dashboard-Views

Length of output: 251


🏁 Script executed:

# Check wp-env config to understand test environment
cat -n tests/E2E/setup/wp-env.config.js | head -50

Repository: GravityKit/Dashboard-Views

Length of output: 665


🌐 Web query:

Playwright test.skip() API correct syntax

💡 Result:

Playwright test.skip() syntax (Playwright Test)

1) Declare a skipped test (never runs)

import { test } from '@playwright/test';

test.skip('never run', async ({ page }) => {
  // ...
});

Also supported:

test.skip(title, details, body);

[1]

2) Skip at runtime (conditional) inside a test (or hook)

test('example', async ({ browserName }) => {
  test.skip(browserName === 'webkit', 'Not supported in WebKit');
  // ... rest of test won't run if condition is true
});

Supported forms:

test.skip(condition, description);
test.skip(callback, description); // for file/describe-wide conditional skipping
test.skip();                      // unconditionally skip all tests in a file or describe block

[1]

3) Skip an entire file (all tests in the file)

import { test } from '@playwright/test';

test.skip(); // applies to the whole file

test('a', async () => {});
test('b', async () => {});

[1]

Note: test.skip() marks a test as skipped (not run). If you intend to come back and fix it, Playwright suggests test.fixme() instead. [1][2]


Guard the license-specific test when license env is not configured.

This test navigates to the GravityKit licenses admin page, which requires a valid license key. With the default empty GRAVITYKIT_LICENSE_KEY in .env.sample, the test will fail even when core activation checks pass. Add a skip guard to prevent failures in local smoke runs without license secrets.

Proposed fix
 test('product is listed as active in GravityKit licenses', async ({ page }) => {
+	test.skip(!process.env.GRAVITYKIT_LICENSE_KEY, 'GRAVITYKIT_LICENSE_KEY is not configured');
+
 	await page.goto('/wp-admin/admin.php?page=gk_licenses&filter=active');
📝 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
test('product is listed as active in GravityKit licenses', async ({ page }) => {
await page.goto('/wp-admin/admin.php?page=gk_licenses&filter=active');
const productCard = page.locator('.sections .grid > div').filter({
has: page.locator('h3', { hasText: 'Dashboard Views' }),
});
await expect(productCard).toBeVisible();
await expect(productCard.locator('button[role="switch"][aria-checked="true"]')).toBeVisible();
});
test('product is listed as active in GravityKit licenses', async ({ page }) => {
test.skip(!process.env.GRAVITYKIT_LICENSE_KEY, 'GRAVITYKIT_LICENSE_KEY is not configured');
await page.goto('/wp-admin/admin.php?page=gk_licenses&filter=active');
const productCard = page.locator('.sections .grid > div').filter({
has: page.locator('h3', { hasText: 'Dashboard Views' }),
});
await expect(productCard).toBeVisible();
await expect(productCard.locator('button[role="switch"][aria-checked="true"]')).toBeVisible();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/E2E/tests/activation.spec.js` around lines 43 - 52, Guard the
end-to-end test that checks GravityKit licenses by skipping it when the license
env var is not provided: wrap or modify the test named "product is listed as
active in GravityKit licenses" (the test(...) block that defines productCard and
assertions) to call Playwright's test.skip when
process.env.GRAVITYKIT_LICENSE_KEY (or equivalent GRAVITYKIT_LICENSE_KEY env) is
falsy, so local runs without a license key do not execute the license-specific
navigation and assertions.

Dashboard Views registers GravityKit Foundation inside the
`gravityview/loaded` action, so when GravityView is not active the
Foundation admin pages (including /wp-admin/admin.php?page=gk_licenses)
are never registered. The license activation smoke test then navigates
to that URL and gets "Sorry, you are not allowed to access this page".

Mirror the existing GravityForms download in the prepare step to also
fetch the latest GravityView release and add it to WP_ENV_PLUGINS so
the hook fires and Foundation registers the licenses page.
Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
.circleci/config.yml (1)

102-103: ⚠️ Potential issue | 🟡 Minor

store_test_results expects a directory path, not a file.

CircleCI's store_test_results requires a directory containing test result files, not a direct file path.

Proposed fix
       - store_test_results:
-          path: tests/E2E/results/junit.xml
+          path: tests/E2E/results
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.circleci/config.yml around lines 102 - 103, The CircleCI step uses
store_test_results with a file path; change it to point at the directory
containing test results instead (replace the path value used with the directory
that contains tests/E2E/results/junit.xml, e.g. tests/E2E/results or the proper
results folder), so update the store_test_results entry (symbol:
store_test_results and its path field) to reference the directory rather than
the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.circleci/config.yml:
- Around line 102-103: The CircleCI step uses store_test_results with a file
path; change it to point at the directory containing test results instead
(replace the path value used with the directory that contains
tests/E2E/results/junit.xml, e.g. tests/E2E/results or the proper results
folder), so update the store_test_results entry (symbol: store_test_results and
its path field) to reference the directory rather than the file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb07966a-5952-427b-981c-1b1a27a95bde

📥 Commits

Reviewing files that changed from the base of the PR and between 88fd1bd and 488d3c0.

📒 Files selected for processing (1)
  • .circleci/config.yml

…ing failure

`package_build` makes a git commit during the packaging step. That triggers
.husky/pre-commit → `npx lint-staged` → `vendor/bin/phpcs`. Because the
preceding `composer install --no-dev` strips phpcs (it is a dev dependency),
the hook fails with `ENOENT` and the job dies before producing any output.

This is a long-standing develop bug — the husky hook was added in
`31290ed Add code sniffer & fix all issues` (Jan 2024) and CI was first
configured in `9ffa680 Configure CI` (May 2024). The two have been
incompatible ever since: every CircleCI run on develop has failed in
the packaging step. It went unnoticed because the failure surfaces at
the very end of the only job in the pipeline and nobody was gating on
it. The new workflow now requires `build_package_release` to succeed
downstream of `run_e2e_tests`, so we have to fix it.

Setting `HUSKY=0` is the standard escape hatch documented by husky for
disabling hooks in non-interactive environments. It scopes the change
to CI only — local pre-commit hooks continue to work for developers.
Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.circleci/config.yml:
- Around line 28-31: The persist_to_workspace configuration currently uses
paths: - . which attempts to persist the workspace root and leaks secrets and
temp files; update the persist_to_workspace entries (the workspace persistence
steps) to remove paths: - . and instead list only the needed directories (e.g.,
plugin and tooling) so only those folders are passed between jobs, and move
creation of the E2E-specific .env (currently created earlier alongside the
Create .npmrc step) into the run_e2e_tests job so the auth token/.env are not
persisted; ensure all workspace persistence blocks (the ones that currently
include '.') are updated consistently and that run_e2e_tests generates the .env
before using it.
- Around line 47-53: The GH release download commands for GravityForms and
GravityView currently omit explicit tags, causing them to fetch the latest
release and drift; update the two invocations of build_tools.sh (the commands
that call "gh -o 'release download -R gravityforms/gravityforms ...'" and "gh -o
'release download -R GravityKit/GravityView ...'") to include explicit release
tags/versions (e.g., use shell variables like GF_TAG/GV_TAG or hardcoded tags)
passed into the 'release download -R ... --clobber --pattern ... --dir ...'
arguments so the E2E job consistently downloads pinned artifact versions.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3372a048-27d2-416f-8829-330bf5bc7b69

📥 Commits

Reviewing files that changed from the base of the PR and between 488d3c0 and c799b1f.

📒 Files selected for processing (1)
  • .circleci/config.yml

Comment thread .circleci/config.yml
Comment on lines +28 to +31
name: Create .npmrc
command: |
echo "//npm.pkg.github.com/:_authToken=${GH_AUTH_TOKEN}" >> ~/.npmrc
echo "@gravitykit:registry=https://npm.pkg.github.com" >> ~/.npmrc
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

git ls-files | grep -E "\.circleci|circleci"

Repository: GravityKit/Dashboard-Views

Length of output: 90


🏁 Script executed:

cat -n .circleci/config.yml | head -100

Repository: GravityKit/Dashboard-Views

Length of output: 4772


🌐 Web query:

CircleCI persist_to_workspace paths root configuration documentation

💡 Result:

In CircleCI config, persist_to_workspace has two required keys:

  • root: a directory on the container that becomes the workspace root for this step. It can be an absolute path or relative to working_directory. [1]
  • paths: a list of files/globs or directories to upload, interpreted relative to root (the workspace root). It must not be the workspace root itself (so paths: ['.'] is invalid if root is .). Patterns use Go’s filepath.Match globbing rules. [1]

Minimal example (persist one file created under workspace/):

- persist_to_workspace:
    root: workspace
    paths:
      - echo-output

A downstream job then downloads the entire workspace and copies it into the directory you choose via attach_workspace:

- attach_workspace:
    at: /tmp/workspace

So the file above becomes available at /tmp/workspace/echo-output. [2]

Sources: CircleCI configuration reference (persist_to_workspace, attach_workspace) [1]; CircleCI “Using workspaces to share data between jobs” guide (end-to-end example) [2].


🏁 Script executed:

cat -n .circleci/config.yml | tail -50

Repository: GravityKit/Dashboard-Views

Length of output: 2668


🏁 Script executed:

# Check for any other setup that creates files in /home/circleci root
rg "home/circleci|~/" .circleci/config.yml -A 2 -B 2

Repository: GravityKit/Dashboard-Views

Length of output: 3975


Remove paths: - . from persist_to_workspace as it violates CircleCI's documented constraint.

CircleCI's configuration reference explicitly states that persist_to_workspace.paths must not reference the workspace root itself. With root: /home/circleci and paths: - ., the configuration attempts to persist the root directory, which is unsupported and will fail.

Beyond the constraint violation, this persists unintended files: the .npmrc file containing the auth token, the .env file with license keys, temporary .tmp artifacts, and other temporary state. Persist only the directories needed downstream (plugin and tooling), and generate the E2E-specific .env inside run_e2e_tests instead.

Suggested change
      - persist_to_workspace:
          root: /home/circleci
          paths:
-           - .
+           - plugin
+           - tooling

Also applies to: 54-57 (move .env creation to run_e2e_tests), 67-70 (workspace paths)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.circleci/config.yml around lines 28 - 31, The persist_to_workspace
configuration currently uses paths: - . which attempts to persist the workspace
root and leaks secrets and temp files; update the persist_to_workspace entries
(the workspace persistence steps) to remove paths: - . and instead list only the
needed directories (e.g., plugin and tooling) so only those folders are passed
between jobs, and move creation of the E2E-specific .env (currently created
earlier alongside the Create .npmrc step) into the run_e2e_tests job so the auth
token/.env are not persisted; ensure all workspace persistence blocks (the ones
that currently include '.') are updated consistently and that run_e2e_tests
generates the .env before using it.

Comment thread .circleci/config.yml
Comment on lines +47 to +53
/home/circleci/tooling/build-tools/build_tools.sh gh -o 'release download -R gravityforms/gravityforms --clobber --pattern "*.zip" --dir .tmp'
unzip .tmp/gravityforms*.zip -d .tmp
# GravityView — Dashboard Views hooks into `gravityview/loaded` to register Foundation,
# so without GravityView active the GK licenses admin page is never registered and the
# license activation smoke test cannot find the product card.
/home/circleci/tooling/build-tools/build_tools.sh gh -o 'release download -R GravityKit/GravityView --clobber --pattern "gravityview-*.zip" --dir .tmp'
unzip .tmp/gravityview-*.zip -d .tmp
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the .circleci/config.yml file and the specific lines mentioned
cat -n .circleci/config.yml | sed -n '40,60p'

Repository: GravityKit/Dashboard-Views

Length of output: 1701


🏁 Script executed:

# Also check the broader context around those lines
cat -n .circleci/config.yml | sed -n '1,70p'

Repository: GravityKit/Dashboard-Views

Length of output: 3497


🌐 Web query:

gh release download default version no tag specified cli.github.com

💡 Result:

With gh release download, the positional argument is the release tag. If you don’t specify a tag, GitHub CLI targets the repo’s latest release, but it requires you to also provide either --pattern or --archive. [1]

Examples:

  • Download a specific asset (or assets) from the latest release:
gh release download --pattern '*.deb'

This works because omitting <tag> means “latest release”. [1]

  • Download the source archive for the latest release:
gh release download --archive=zip

[1]

  • Download all assets from the latest release (by first resolving the latest tag, then downloading by tag):
tag="$(gh release view --json tagName --jq .tagName)"
gh release download "$tag"

gh release view shows the latest release when no tag is provided, and tagName is available via --json. [2]

Sources:
[1] gh release download manual (GitHub CLI)
[2] gh release view manual (GitHub CLI)


🏁 Script executed:

# Search for GRAVITYFORMS_RELEASE and GRAVITYVIEW_RELEASE in the config
rg 'GRAVITYFORMS_RELEASE|GRAVITYVIEW_RELEASE' .circleci/config.yml

Repository: GravityKit/Dashboard-Views

Length of output: 52


🏁 Script executed:

# Check if there are any environment variable definitions in the config
grep -n "env:" .circleci/config.yml | head -20

Repository: GravityKit/Dashboard-Views

Length of output: 52


🏁 Script executed:

# Look for any variables section or environment setup
cat -n .circleci/config.yml | grep -A 5 -B 5 "variables:\|environment:"

Repository: GravityKit/Dashboard-Views

Length of output: 1258


🏁 Script executed:

# Search the entire repo for GRAVITYFORMS_RELEASE or GRAVITYVIEW_RELEASE
rg 'GRAVITYFORMS_RELEASE|GRAVITYVIEW_RELEASE' --type yml --type yaml --type md

Repository: GravityKit/Dashboard-Views

Length of output: 97


🏁 Script executed:

# Check the README or any documentation for E2E setup
find . -maxdepth 2 -name "README*" -o -name "*.md" | head -10

Repository: GravityKit/Dashboard-Views

Length of output: 81


🏁 Script executed:

# Search more broadly for these variables
rg 'GRAVITYFORMS_RELEASE|GRAVITYVIEW_RELEASE'

Repository: GravityKit/Dashboard-Views

Length of output: 52


🏁 Script executed:

# Check the README for E2E setup instructions
cat readme.md | grep -A 10 -B 5 -i "gravityforms\|gravityview\|e2e\|release"

Repository: GravityKit/Dashboard-Views

Length of output: 1106


🏁 Script executed:

# Check if there's a .env.sample mentioned in config
cat -n .env.sample 2>/dev/null | head -30

Repository: GravityKit/Dashboard-Views

Length of output: 677


🏁 Script executed:

# Check CircleCI documentation/scripts to see if there's any release pinning mechanism
find . -name "*.sh" -o -name "*circleci*" | head -20

Repository: GravityKit/Dashboard-Views

Length of output: 81


🏁 Script executed:

# Look for any other CircleCI configuration files that might define variables
find . -path "./.circleci*" -type f

Repository: GravityKit/Dashboard-Views

Length of output: 92


🌐 Web query:

gh release download tag syntax --pattern example

💡 Result:

gh release download syntax:

  • With an explicit tag:
    gh release download <tag> [--pattern <glob> ...]
  • Without a tag (downloads “latest” release): you must pass either --pattern or --archive. [1]

--pattern takes glob patterns (you can repeat it):

# Download all assets from tag v1.2.3
gh release download v1.2.3
# Download only matching assets from the latest release
gh release download --pattern '*.deb'
# Multiple patterns
gh release download -p '*.deb' -p '*.rpm'
# Filter assets from a specific tag
gh release download v1.2.3 --pattern '*linux*amd64*.tar.gz'

[1]


Pin the upstream plugin releases used by E2E.

gh release download pulls assets from the latest release when no tag is provided. These two downloads will drift as GravityForms or GravityView publish new releases, so the smoke suite can start failing on unrelated upstream changes and become hard to reproduce. Pass explicit release tags/versions into both commands instead of relying on "latest."

Suggested change
+            : "${GRAVITYFORMS_RELEASE:?Missing GRAVITYFORMS_RELEASE}"
+            : "${GRAVITYVIEW_RELEASE:?Missing GRAVITYVIEW_RELEASE}"
-            /home/circleci/tooling/build-tools/build_tools.sh gh -o 'release download -R gravityforms/gravityforms --clobber --pattern "*.zip" --dir .tmp'
+            /home/circleci/tooling/build-tools/build_tools.sh gh -o "release download ${GRAVITYFORMS_RELEASE} -R gravityforms/gravityforms --clobber --pattern '*.zip' --dir .tmp"
             unzip .tmp/gravityforms*.zip -d .tmp
-            /home/circleci/tooling/build-tools/build_tools.sh gh -o 'release download -R GravityKit/GravityView --clobber --pattern "gravityview-*.zip" --dir .tmp'
+            /home/circleci/tooling/build-tools/build_tools.sh gh -o "release download ${GRAVITYVIEW_RELEASE} -R GravityKit/GravityView --clobber --pattern 'gravityview-*.zip' --dir .tmp"
             unzip .tmp/gravityview-*.zip -d .tmp
📝 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
/home/circleci/tooling/build-tools/build_tools.sh gh -o 'release download -R gravityforms/gravityforms --clobber --pattern "*.zip" --dir .tmp'
unzip .tmp/gravityforms*.zip -d .tmp
# GravityView — Dashboard Views hooks into `gravityview/loaded` to register Foundation,
# so without GravityView active the GK licenses admin page is never registered and the
# license activation smoke test cannot find the product card.
/home/circleci/tooling/build-tools/build_tools.sh gh -o 'release download -R GravityKit/GravityView --clobber --pattern "gravityview-*.zip" --dir .tmp'
unzip .tmp/gravityview-*.zip -d .tmp
: "${GRAVITYFORMS_RELEASE:?Missing GRAVITYFORMS_RELEASE}"
: "${GRAVITYVIEW_RELEASE:?Missing GRAVITYVIEW_RELEASE}"
/home/circleci/tooling/build-tools/build_tools.sh gh -o "release download ${GRAVITYFORMS_RELEASE} -R gravityforms/gravityforms --clobber --pattern '*.zip' --dir .tmp"
unzip .tmp/gravityforms*.zip -d .tmp
# GravityView — Dashboard Views hooks into `gravityview/loaded` to register Foundation,
# so without GravityView active the GK licenses admin page is never registered and the
# license activation smoke test cannot find the product card.
/home/circleci/tooling/build-tools/build_tools.sh gh -o "release download ${GRAVITYVIEW_RELEASE} -R GravityKit/GravityView --clobber --pattern 'gravityview-*.zip' --dir .tmp"
unzip .tmp/gravityview-*.zip -d .tmp
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.circleci/config.yml around lines 47 - 53, The GH release download commands
for GravityForms and GravityView currently omit explicit tags, causing them to
fetch the latest release and drift; update the two invocations of build_tools.sh
(the commands that call "gh -o 'release download -R gravityforms/gravityforms
...'" and "gh -o 'release download -R GravityKit/GravityView ...'") to include
explicit release tags/versions (e.g., use shell variables like GF_TAG/GV_TAG or
hardcoded tags) passed into the 'release download -R ... --clobber --pattern ...
--dir ...' arguments so the E2E job consistently downloads pinned artifact
versions.

@Mwalek Mwalek requested a review from mrcasual April 8, 2026 10:55
Clicks the GravityView deactivate link on the plugins page and asserts
that a browser dialog containing "GravityView is required by" is shown.
Accepts the dialog, then re-activates GravityView so subsequent tests
are unaffected.
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.

1 participant