diff --git a/apps/cli/commands/site/tests/create.e2e.test.ts b/apps/cli/commands/site/tests/create.e2e.test.ts index 26f2892a3b..402ccd8901 100644 --- a/apps/cli/commands/site/tests/create.e2e.test.ts +++ b/apps/cli/commands/site/tests/create.e2e.test.ts @@ -35,7 +35,7 @@ describe.skipIf( ! cliE2ePrerequisitesMet() )( 'CLI e2e: studio site create', () }, 60_000 ); it( - 'creates a site that serves its homepage', + 'creates a site that serves its homepage and signs in with its admin credentials', { tags: [ 'e2e' ], timeout: 180_000 }, async () => { env = setupCliEnv(); @@ -52,6 +52,10 @@ describe.skipIf( ! cliE2ePrerequisitesMet() )( 'CLI e2e: studio site create', () sitePath, '--wp', 'latest', + '--admin-username', + 'navigator', + '--admin-password', + 'e2e-created-password', '--skip-browser', '--skip-log-details', ], @@ -79,6 +83,18 @@ describe.skipIf( ! cliE2ePrerequisitesMet() )( 'CLI e2e: studio site create', () } ); expect( response.status ).toBe( 200 ); expect( response.headers.get( 'content-type' ) ).toMatch( /text\/html/ ); + + const signIn = await fetch( `http://localhost:${ String( site.port ) }/wp-login.php`, { + method: 'POST', + headers: { + 'content-type': 'application/x-www-form-urlencoded', + // wp-login.php rejects the sign-in without WordPress's test cookie. + cookie: 'wordpress_test_cookie=WP%20Cookie%20check', + }, + body: new URLSearchParams( { log: 'navigator', pwd: 'e2e-created-password' } ), + redirect: 'manual', + } ); + expect( signIn.headers.get( 'set-cookie' ) ).toContain( 'wordpress_logged_in' ); } ); diff --git a/apps/cli/lib/native-php/site-setup.ts b/apps/cli/lib/native-php/site-setup.ts index 7a2bed3089..d4c756a141 100644 --- a/apps/cli/lib/native-php/site-setup.ts +++ b/apps/cli/lib/native-php/site-setup.ts @@ -169,17 +169,21 @@ function isCoreLanguagePackInstalled( sitePath: string, locale: string ): boolea ); } +/** + * Installs WordPress unless it already is. Returns whether it ran the installer, + * which also creates the admin user with the configured credentials. + */ export async function installWordPress( config: ServerConfig, phpVersion: SupportedPHPVersion, signal: AbortSignal, finishInstallPath: string, logToConsole: Logger -): Promise< void > { +): Promise< boolean > { const alreadyInstalled = await isWordPressInstalled( config.sitePath, phpVersion, signal ); if ( alreadyInstalled ) { logToConsole( `WordPress already installed; skipping installer` ); - return; + return false; } const siteTitle = config.siteTitle ?? 'My WordPress Website'; @@ -248,4 +252,5 @@ export async function installWordPress( ); } } + return true; } diff --git a/apps/cli/php-server-child.ts b/apps/cli/php-server-child.ts index c46989225c..44bcd79972 100644 --- a/apps/cli/php-server-child.ts +++ b/apps/cli/php-server-child.ts @@ -473,6 +473,9 @@ async function startServer( config: ServerConfig, signal: AbortSignal ): Promise // against the imported database would be wrong — and just write Studio's // mu-plugins before starting the workers. const isImportedSite = Boolean( config.autoPrependFile ); + // Set when this start ran the installer, which created the admin user with the + // configured credentials, and no Blueprint ran after it that could change them. + let credentialsJustInstalled = false; try { stopSignal.throwIfAborted(); @@ -488,12 +491,13 @@ async function startServer( config: ServerConfig, signal: AbortSignal ): Promise stopSignal.throwIfAborted(); if ( ! isImportedSite ) { - await timePhase( 'wordpress_install', () => + const installed = await timePhase( 'wordpress_install', () => installWordPress( config, phpVersion, stopSignal, FINISH_INSTALL_PATH, logToConsole ) ); stopSignal.throwIfAborted(); const blueprint = config.blueprint; + credentialsJustInstalled = installed && ! blueprint; if ( blueprint ) { await timePhase( 'blueprint', () => runBlueprint( config, blueprint, phpVersion, stopSignal ) @@ -543,8 +547,10 @@ async function startServer( config: ServerConfig, signal: AbortSignal ): Promise phpProcess = await doStartServer( config, stopSignal ); stopSignal.throwIfAborted(); - await timePhase( 'admin_credentials', () => setAdminCredentials( config, stopSignal ) ); - stopSignal.throwIfAborted(); + if ( ! credentialsJustInstalled ) { + await timePhase( 'admin_credentials', () => setAdminCredentials( config, stopSignal ) ); + stopSignal.throwIfAborted(); + } } catch ( error ) { killPhpProcess(); phpProcess = null;