Skip to content

Add CLI integration test for site create (custom name, domain, HTTPS)#3947

Merged
gavande1 merged 3 commits into
trunkfrom
stu-1867-add-cli-create-e2e-test
Jun 26, 2026
Merged

Add CLI integration test for site create (custom name, domain, HTTPS)#3947
gavande1 merged 3 commits into
trunkfrom
stu-1867-add-cli-create-e2e-test

Conversation

@gavande1

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Proposed Changes

The end-to-end suite drives every site action through the Studio UI, which is slow, flaky, and ties coverage to the UI. This adds the first real CLI integration test for studio site create: it runs the actual command against an isolated config directory and asserts on the persisted result, covering a site with a custom name and a site with a custom domain plus HTTPS. The tests are tagged e2e so they run in the slower release or manual suite rather than on every pull request.

Testing Instructions

  1. Build the CLI with npm run cli:build.
  2. Run npm test -- --tagsFilter='e2e' and confirm both tests pass.
  3. Run npm test -- --tagsFilter='!e2e' and confirm these tests are skipped, so the fast suite is unaffected.

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

@gcsecsey gcsecsey marked this pull request as ready for review June 25, 2026 11:35
@gcsecsey gcsecsey requested a review from fredrikekelund June 25, 2026 11:35

@gcsecsey gcsecsey left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice work @gavande1, spawning the CLI and asserting against files on disk is a good direction for these tests IMO.

The two tests cases added here LGTM, and we can add more incrementally as needed.

Comment thread apps/cli/commands/site/tests/helpers/cli-e2e.ts
@gavande1 gavande1 disabled auto-merge June 26, 2026 07:01
@gavande1 gavande1 enabled auto-merge (squash) June 26, 2026 07:03
@wpmobilebot

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing ed958ee vs trunk

app-size

Metric trunk ed958ee Diff Change
App Size (Mac) 1315.48 MB 1315.48 MB +0.00 MB ⚪ 0.0%

site-editor

Metric trunk ed958ee Diff Change
load 1047 ms 1043 ms 4 ms ⚪ 0.0%

site-startup

Metric trunk ed958ee Diff Change
siteCreation 6479 ms 6469 ms 10 ms ⚪ 0.0%
siteStartup 7005 ms 6983 ms 22 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@gavande1 gavande1 merged commit 21f7d1a into trunk Jun 26, 2026
11 checks passed
@gavande1 gavande1 deleted the stu-1867-add-cli-create-e2e-test branch June 26, 2026 07:18
gcsecsey added a commit that referenced this pull request Jun 29, 2026
…3961)

## Related issues

- Fixes STU-1871
- Stacked on #3947

## How AI was used in this PR

I used Claude to review the existing Playwright blueprint tests and the
new CLI e2e harness from #3947, plan the migration, and to write the
test. I reviewd and verified all changes.

## Proposed Changes

Blueprint coverage currently lives only in
`apps/studio/e2e/blueprints.test.ts`, which boots the entire desktop app
through Playwright to create a site from a custom Blueprint and then
inspects wp-admin — slow, flaky, and coupled to the UI. This PR
continues the "Migrate Studio E2E tests to CLI" effort by exercising the
same capability directly through the CLI.

- Adds integration tests that run `studio site create --blueprint
<file>` against an isolated config directory and asserts on the file
system.
- Closes a gap in the #3947 harness: the helper isolated the config
directory but not the legacy Electron appdata directory, so the
Studio-compatibility startup migration could find a real pre-split
`appdata-v1.json` and abort the CLI on a developer's machine. The
harness now also isolates that path, which fixes the sibling
`create.e2e.test.ts` locally.

## Testing Instructions

1. Build the CLI: `npm run cli:build`.
2. Run the new suite (needs a network connection for the download
install step):
`npm test -- apps/cli/commands/site/tests/create-blueprint.e2e.test.ts
--tagsFilter='e2e'`
   Confirm all four tests pass.
3. Confirm the fast suite is unaffected:
`npm test -- apps/cli/commands/site/tests/create-blueprint.e2e.test.ts
--tagsFilter='!e2e'`
   The four tests are skipped.
4. Regression check for the harness fix — confirm the sibling test also
passes:
`npm test -- apps/cli/commands/site/tests/create.e2e.test.ts
--tagsFilter='e2e'`

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?

---------

Co-authored-by: Rahul Gavande <rahul.gavande@automattic.com>

@fredrikekelund fredrikekelund left a comment

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.

I left some comments about doing HTTP requests to the site's homepage after running the site create commands. The fundamentals here look really good, though 👍

Comment on lines +56 to +70
expect( result.code, result.stderr ).toBe( 0 );

// The site is persisted to the real cli.json with the custom name.
const config = readCliConfig( env );
expect( config.sites ).toHaveLength( 1 );
const [ site ] = config.sites;
expect( site.name ).toBe( siteName );
expect( site.path ).toBe( sitePath );
expect( site.phpVersion ).toBeTruthy();
expect( site.running ).toBe( false );

// Real WordPress core files were copied into the site directory.
// (wp-config.php is generated at server start, which --no-start skips.)
expect( fs.existsSync( path.join( sitePath, 'wp-load.php' ) ) ).toBe( true );
expect( fs.existsSync( path.join( sitePath, 'wp-includes', 'version.php' ) ) ).toBe( true );

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.

I'd add an HTTP request that verifies that we get a 200 OK HTTP response from the site. Either we need to parse the regular stdout output from the site create command, or we add a --format=json parameter (that's the kind of change I was talking about in our huddle where working on the test suite might uncover flaws in the CLI implementation)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in #4000. The create test now starts the site and asserts a 200 with HTML from the homepage.

type CliEnv,
} from './helpers/cli-e2e';

describe.skipIf( ! cliE2ePrerequisitesMet() )( 'CLI e2e: studio site create', () => {

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.

It seems more helpful if the test would break rather than gracefully skip if the CLI artifacts don't exist.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We already have open issue to handle CLI tests.

Comment on lines +102 to +114
expect( result.code, result.stderr ).toBe( 0 );

// The custom domain and HTTPS preference are persisted to cli.json.
// (--no-start skips the hosts-file / certificate setup that running would do.)
const config = readCliConfig( env );
expect( config.sites ).toHaveLength( 1 );
const [ site ] = config.sites;
expect( site.name ).toBe( siteName );
expect( site.customDomain ).toBe( customDomain );
expect( site.enableHttps ).toBe( true );
expect( site.running ).toBe( false );

expect( fs.existsSync( path.join( sitePath, 'wp-load.php' ) ) ).toBe( true );

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.

Same thing here about adding an HTTP request for verification

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I kept the custom-domain and HTTPS case as persistence-only. Serving it needs the full stack: the proxy on ports 80 and 443, a trusted root CA, and a write to the shared /etc/hosts behind an elevated-privileges prompt, so it cannot run in an isolated, headless test. The live check stays on the plain localhost site in #4000.

version: 1,
sites: [],
snapshots: [],
lastDependencyCheckTime: Date.now(),

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.

Nice 👍

@gavande1

gavande1 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the review @fredrikekelund. I have addressed your comments in #4000.

gcsecsey added a commit that referenced this pull request Jun 30, 2026
## Related issues

- Fixes STU-1868
- Builds on #3947 (the `site create` integration test + e2e harness) and
complements the UI suite in #3950

## How AI was used in this PR

I used Claude to write the test and the harness changes, and traced the
daemon connection failures to a Unix socket path length limit. I
reviewed the diff, ran the suite on nodes 22 and 24, and confirmed that
runs are isolated, with no orphan daemons/servers and no temp-dir leaks.

## Proposed Changes

We're migrating the legacy blueprint-based start/stop test cases to the
CLI integration approach. The existing `start.test.ts` / `stop.test.ts`
unit tests mock the daemon and server manager. This PR instead boots a
real WordPress server through the process-manager daemon and verifies
the live running state via `site list --format json`, so it actually
exercises the daemon -> server -> port lifecycle.

- Adds an `e2e`-tagged suite that creates a site with `--no-start`. It
runs in the slower (release/manual) suite, not on every PR.
- Updates the harness to prevent the tests affecting local sites. The
lifecycle commands talk to the process-manager daemon, and the cleanup
step `stop --all` would kill the developer's real running sites. The
harness now gives each run its own daemon home via
`STUDIO_PROCESS_MANAGER_HOME`, so runs are fully isolated and
parallel-safe. That home is deliberately kept short and under the temp
dir: the daemon's control socket is a Unix domain socket, and nesting it
under the `studio-cli-e2e-<uuid>` root path overflows macOS's 104-char
socket path limit. This surfaces as `EINVAL` on node 24 and as an
indefinite connect-retry (hang) on node 22. Windows uses a fixed named
pipe, so this isolation is macOS/Linux only.
- The harness also seeds a minimal `app.json` so the
`00-check-studio-compatibility` migration returns early. Without it,
that migration falls through to the developer's real legacy app data and
aborts the CLI, so the suite would pass on CI yet fail on a dev machine
with Studio installed. This also retroactively hardens the `site create`
test from #3947, which carries the same gap.
- Uses `--runtime sandbox` to stay hermetic. The native PHP runtime
drives the same lifecycle but downloads its ~25 MB binary into the
isolated config dir on the first run. Covering it hermetically needs CI
to provision that binary, so native-PHP coverage is a follow-up.

## Testing Instructions

1. `npm run cli:build`
2. `npm test -- --tagsFilter='e2e'
apps/cli/commands/site/tests/start-stop.e2e.test.ts`
3. Expect 2 tests green (`starts a site`, `stops a site`).
4. While it runs, confirm it does not disturb sites you have running in
Studio, and leaves no orphan processes or temp dirs afterward.

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?
gcsecsey added a commit that referenced this pull request Jul 1, 2026
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