Skip to content

Commit

Permalink
[CMSP-1140] add Playwright tests for multisite (#140)
Browse files Browse the repository at this point in the history
* abstract out the site_id and pass a site url to playwright
we can copy this pattern for subdomain and subdirectory multisites

* allow site name to come from environment

* move playwright tests to repeatable composate action

* run actions/checkout first
maybe remove this from composite?

* remove checkout from composite action

* Update playwright.yml to use the correct path for run-playwright-tests

* pass all the parameters from the workflow that has that info

* add shell

* add logging

* log the deletion, too

* pass the site name to the playwright tests

* fix broken colors

* add stdbuf to commands to log everything to the terminal

* shorten the names
so they're easier to read in the action workflow

* set the upstream id

* reference the action file directly

* create application.php files for subdir & subdom multisite

* copy the config file to the config/ directory

* absolutely do not use the action.yml path

* fix linting in two new files

* just use actual upstream IDs
instead of the upstream name

* remove comment
this isn't relevant anymore

* don't set the ID to the new ID
set the var to the id 🤦‍♂️

* check the multisite install when we status check

* fix broken conditional

* the conditional needs to wrap around the whole multisite block

* add a db reset before site install

* add the updated application.php file before the multisite check

* make sure we're in the right directory

* rename the file

* be specific about the type of multisite in the commit message

* move the wait to the top
so we can wait for the previous commit to finish

* use the correct site url (not the copy pasta one)

* display art for no good reason

* wait for the config to hit the server
because otherwise we're checking for the install status too early

* yeah 🤦‍♂️

* I guess we just can't do a colored logo

* set a max wait on the wait before installing graphql
because if a process is running, it'll wait longer, but if a process isn't (like we already waited earlier) then it's just going to use the long timeout

* only add the subsite if it doesn't already exist

* split the clone and copy updates apart
and put the multisite config in the middle
this way we're only waiting for sync_code once

* we do actually need the github token

* fix typo

* don't fail if there's nothing to commit

* just see if a foo site exists

* break the composite workflow into a script

* PRIVATE_KEY not SSH_KEY

* fix terminus token, too

* set defaults & move functions to the bottom

* shellcheck

* fix the other places inputs were broken

* fix secret name

* delete the sites when we're done

* remove any exits that aren't errors

* fix file copy globbing

* remove composite action

* move install dependencies into action & pantheon host key into script

* get last commit message and export to the environment

* remove host key command
we're still doing it in the action and it works for single site

* use the github token

* cd to the workspace

* need to get PR number

* echo the commit message for debugging

* use upstream name instead of id

* move playwright tests into the main workflow

* remove the blue var
unused

* need to install deps in single site

* multisite doesn't add host key
copy/pasta the two setups around keys and terminus so it's consistent

* rename run-playwright-tests to setup-

* Commit GraphQL to the repo

* move the workflow:wait to after we copy updates
because we're, again, checking multisite config before the commit is there

* use test instead of comparing value
i think this is failing because it's returning empty when it's not set

* don't use test, just run the command

* set connection to git always

* store the value of the config get in a var and check that

* install wp before doing status check

* fix subdir siet url vars

* force db reset

* the script shouldn't fail if foo site isn't found

* fix site title

* store site name and url in Github env

* normalize rest endpoint for multisite

* separately apply the filter to rest urls

* filter the rest endpoint, too

* remove all the wp-json handling

* adjust the playwright test to expect the api endpoint to be /wp/wp-json

* change the site name before we test the subsite

* the graphql endpoint changes if we're on a subsite, too

* flush the cache for the sub-site if we're doing multisite

* fix the toBeTruthy check

* echo with -e for color

* fix spacing

* only log in if not already logged in
allows you to run this locally with existing terminus token

* don't flush permalinks here
they're flushed after the site is created

* add tests for subdomain

* fix the subdom site url

* [CMSP-1140] Move cookie settings down to use Pantheon hostname (#141)

move cookie settings down so we can use pantheon hostname

* wrap PANTHEON_ENVIRONMENT with an isset

* remove the comment

Co-authored-by: Phil Tyler <[email protected]>

* make the globals readonly

TIL ✨

Co-authored-by: Phil Tyler <[email protected]>

* return early

don't exit because that bails the script

Co-authored-by: Phil Tyler <[email protected]>

* use `[[` instead of `[`

Co-authored-by: Phil Tyler <[email protected]>

* return early

Co-authored-by: Phil Tyler <[email protected]>

* one terminus command to activate wp-graphql

Co-authored-by: Phil Tyler <[email protected]>

* use brackets around commit msg

* use printf to handle single quotes in commit messages

* skip creating a new variable if we do not need it

Co-authored-by: Phil Tyler <[email protected]>

* strip out single quotes
this won't catch everything but maybe it'll catch what's breaking things now

* better handling of sed

* use printf

* strip newlines and carriage returns

* better commit message cleaning

---------

Co-authored-by: Phil Tyler <[email protected]>
  • Loading branch information
jazzsequence and pwtyler authored Jul 18, 2024
1 parent affa192 commit 03c8f04
Show file tree
Hide file tree
Showing 7 changed files with 796 additions and 100 deletions.
173 changes: 173 additions & 0 deletions .github/fixtures/config/application.subdir.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php
/**
* Your base production configuration goes in this file.
*
* A good default policy is to deviate from the production config as little as
* possible. Try to define as much of your configuration in this file as you
* can.
*/

use Roots\WPConfig\Config;
use function Env\env;

// USE_ENV_ARRAY + CONVERT_* + STRIP_QUOTES.
Env\Env::$options = 31;

/**
* Directory containing all of the site's files
*
* @var string
*/
$root_dir = dirname( __DIR__ );

/**
* Document Root
*
* @var string
*/
$webroot_dir = $root_dir . '/web';

/**
* Use Dotenv to set required environment variables and load .env file in root
* .env.local will override .env if it exists
*/
$env_files = file_exists( $root_dir . '/.env.local' )
? [ '.env', '.env.pantheon', '.env.local' ]
: [ '.env', '.env.pantheon' ];

$dotenv = Dotenv\Dotenv::createImmutable( $root_dir, $env_files, false );
if (
// Check if a .env file exists.
file_exists( $root_dir . '/.env' ) ||
// Also check if we're using Lando and a .env.local file exists.
( file_exists( $root_dir . '/.env.local' ) && isset( $_ENV['LANDO'] ) && 'ON' === $_ENV['LANDO'] )
) {
$dotenv->load();
if ( ! env( 'DATABASE_URL' ) ) {
$dotenv->required( [ 'DB_NAME', 'DB_USER', 'DB_PASSWORD' ] );
}
}

/**
* Include Pantheon application settings.
*/
require_once __DIR__ . '/application.pantheon.php';

/**
* Set up our global environment constant and load its config first
* Default: production
*/
define( 'WP_ENV', env( 'WP_ENV' ) ?: 'production' );

/**
* DB settings
*/
Config::define( 'DB_NAME', env( 'DB_NAME' ) );
Config::define( 'DB_USER', env( 'DB_USER' ) );
Config::define( 'DB_PASSWORD', env( 'DB_PASSWORD' ) );
Config::define( 'DB_HOST', env( 'DB_HOST' ) ?: 'localhost' );
Config::define( 'DB_CHARSET', 'utf8mb4' );
Config::define( 'DB_COLLATE', '' );
$table_prefix = env( 'DB_PREFIX' ) ?: 'wp_';

if ( env( 'DATABASE_URL' ) ) {
$dsn = (object) parse_url( env( 'DATABASE_URL' ) );

Config::define( 'DB_NAME', substr( $dsn->path, 1 ) );
Config::define( 'DB_USER', $dsn->user );
Config::define( 'DB_PASSWORD', isset( $dsn->pass ) ? $dsn->pass : null );
Config::define( 'DB_HOST', isset( $dsn->port ) ? "{$dsn->host}:{$dsn->port}" : $dsn->host );
}

/**
* Pantheon modifications
*/
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && ! isset( $_ENV['LANDO'] ) ) {
Config::define( 'DB_HOST', $_ENV['DB_HOST'] . ':' . $_ENV['DB_PORT'] );
} else {
/**
* URLs
*/
Config::define( 'WP_HOME', env( 'WP_HOME' ) );
Config::define( 'WP_SITEURL', env( 'WP_SITEURL' ) );
Config::define( 'DB_HOST', env( 'DB_HOST' ) ?: 'localhost' );
}

/**
* Custom Content Directory
*/
Config::define( 'CONTENT_DIR', '/app' );
Config::define( 'WP_CONTENT_DIR', $webroot_dir . Config::get( 'CONTENT_DIR' ) );
Config::define( 'WP_CONTENT_URL', Config::get( 'WP_HOME' ) . Config::get( 'CONTENT_DIR' ) );

/**
* Authentication Unique Keys and Salts
*/
Config::define( 'AUTH_KEY', env( 'AUTH_KEY' ) );
Config::define( 'SECURE_AUTH_KEY', env( 'SECURE_AUTH_KEY' ) );
Config::define( 'LOGGED_IN_KEY', env( 'LOGGED_IN_KEY' ) );
Config::define( 'NONCE_KEY', env( 'NONCE_KEY' ) );
Config::define( 'AUTH_SALT', env( 'AUTH_SALT' ) );
Config::define( 'SECURE_AUTH_SALT', env( 'SECURE_AUTH_SALT' ) );
Config::define( 'LOGGED_IN_SALT', env( 'LOGGED_IN_SALT' ) );
Config::define( 'NONCE_SALT', env( 'NONCE_SALT' ) );

/**
* Multisite
*/
Config::define( 'MULTISITE', true );
Config::define( 'SUBDOMAIN_INSTALL', false );
Config::define( 'DOMAIN_CURRENT_SITE', defined( 'PANTHEON_HOSTNAME' ) ? PANTHEON_HOSTNAME : $_SERVER['HTTP_HOST'] );
Config::define( 'PATH_CURRENT_SITE', '/' );
Config::define( 'SITE_ID_CURRENT_SITE', 1 );
Config::define( 'BLOG_ID_CURRENT_SITE', 1 );
Config::define( 'WP_ALLOW_MULTISITE', env( 'WP_ALLOW_MULTISITE' ) ?: true );

/**
* Custom Settings
*/
Config::define( 'AUTOMATIC_UPDATER_DISABLED', true );
// Disable the plugin and theme file editor in the admin.
Config::define( 'DISALLOW_FILE_EDIT', true );
// Disable plugin and theme updates and installation from the admin.
Config::define( 'DISALLOW_FILE_MODS', true );
// Limit the number of post revisions that Wordpress stores (true (default WP): store every revision).
Config::define( 'WP_POST_REVISIONS', env( 'WP_POST_REVISIONS' ) ?? true );

/**
* Debugging Settings
*/
if ( ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && $_ENV['PANTHEON_ENVIRONMENT'] === 'dev' ) || isset( $_ENV['LANDO'] ) ) {
Config::define( 'WP_DEBUG_DISPLAY', true );
Config::define( 'WP_DEBUG_LOG', true );
Config::define( 'SCRIPT_DEBUG', true );
ini_set( 'display_errors', '1' );
} else {
Config::define( 'WP_DEBUG_DISPLAY', false );
Config::define( 'WP_DEBUG_LOG', false );
Config::define( 'SCRIPT_DEBUG', false );
ini_set( 'display_errors', '0' );
}

/**
* Allow WordPress to detect HTTPS when used behind a reverse proxy or a load balancer
* See https://codex.wordpress.org/Function_Reference/is_ssl#Notes
*/
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}

$env_config = __DIR__ . '/environments/' . WP_ENV . '.php';

if ( file_exists( $env_config ) ) {
require_once $env_config;
}

Config::apply();

/**
* Bootstrap WordPress
*/
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', $webroot_dir . '/wp/' );
}
173 changes: 173 additions & 0 deletions .github/fixtures/config/application.subdom.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php
/**
* Your base production configuration goes in this file.
*
* A good default policy is to deviate from the production config as little as
* possible. Try to define as much of your configuration in this file as you
* can.
*/

use Roots\WPConfig\Config;
use function Env\env;

// USE_ENV_ARRAY + CONVERT_* + STRIP_QUOTES.
Env\Env::$options = 31;

/**
* Directory containing all of the site's files
*
* @var string
*/
$root_dir = dirname( __DIR__ );

/**
* Document Root
*
* @var string
*/
$webroot_dir = $root_dir . '/web';

/**
* Use Dotenv to set required environment variables and load .env file in root
* .env.local will override .env if it exists
*/
$env_files = file_exists( $root_dir . '/.env.local' )
? [ '.env', '.env.pantheon', '.env.local' ]
: [ '.env', '.env.pantheon' ];

$dotenv = Dotenv\Dotenv::createImmutable( $root_dir, $env_files, false );
if (
// Check if a .env file exists.
file_exists( $root_dir . '/.env' ) ||
// Also check if we're using Lando and a .env.local file exists.
( file_exists( $root_dir . '/.env.local' ) && isset( $_ENV['LANDO'] ) && 'ON' === $_ENV['LANDO'] )
) {
$dotenv->load();
if ( ! env( 'DATABASE_URL' ) ) {
$dotenv->required( [ 'DB_NAME', 'DB_USER', 'DB_PASSWORD' ] );
}
}

/**
* Include Pantheon application settings.
*/
require_once __DIR__ . '/application.pantheon.php';

/**
* Set up our global environment constant and load its config first
* Default: production
*/
define( 'WP_ENV', env( 'WP_ENV' ) ?: 'production' );

/**
* DB settings
*/
Config::define( 'DB_NAME', env( 'DB_NAME' ) );
Config::define( 'DB_USER', env( 'DB_USER' ) );
Config::define( 'DB_PASSWORD', env( 'DB_PASSWORD' ) );
Config::define( 'DB_HOST', env( 'DB_HOST' ) ?: 'localhost' );
Config::define( 'DB_CHARSET', 'utf8mb4' );
Config::define( 'DB_COLLATE', '' );
$table_prefix = env( 'DB_PREFIX' ) ?: 'wp_';

if ( env( 'DATABASE_URL' ) ) {
$dsn = (object) parse_url( env( 'DATABASE_URL' ) );

Config::define( 'DB_NAME', substr( $dsn->path, 1 ) );
Config::define( 'DB_USER', $dsn->user );
Config::define( 'DB_PASSWORD', isset( $dsn->pass ) ? $dsn->pass : null );
Config::define( 'DB_HOST', isset( $dsn->port ) ? "{$dsn->host}:{$dsn->port}" : $dsn->host );
}

/**
* Pantheon modifications
*/
if ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && ! isset( $_ENV['LANDO'] ) ) {
Config::define( 'DB_HOST', $_ENV['DB_HOST'] . ':' . $_ENV['DB_PORT'] );
} else {
/**
* URLs
*/
Config::define( 'WP_HOME', env( 'WP_HOME' ) );
Config::define( 'WP_SITEURL', env( 'WP_SITEURL' ) );
Config::define( 'DB_HOST', env( 'DB_HOST' ) ?: 'localhost' );
}

/**
* Custom Content Directory
*/
Config::define( 'CONTENT_DIR', '/app' );
Config::define( 'WP_CONTENT_DIR', $webroot_dir . Config::get( 'CONTENT_DIR' ) );
Config::define( 'WP_CONTENT_URL', Config::get( 'WP_HOME' ) . Config::get( 'CONTENT_DIR' ) );

/**
* Authentication Unique Keys and Salts
*/
Config::define( 'AUTH_KEY', env( 'AUTH_KEY' ) );
Config::define( 'SECURE_AUTH_KEY', env( 'SECURE_AUTH_KEY' ) );
Config::define( 'LOGGED_IN_KEY', env( 'LOGGED_IN_KEY' ) );
Config::define( 'NONCE_KEY', env( 'NONCE_KEY' ) );
Config::define( 'AUTH_SALT', env( 'AUTH_SALT' ) );
Config::define( 'SECURE_AUTH_SALT', env( 'SECURE_AUTH_SALT' ) );
Config::define( 'LOGGED_IN_SALT', env( 'LOGGED_IN_SALT' ) );
Config::define( 'NONCE_SALT', env( 'NONCE_SALT' ) );

/**
* Multisite
*/
Config::define( 'MULTISITE', true );
Config::define( 'SUBDOMAIN_INSTALL', true );
Config::define( 'DOMAIN_CURRENT_SITE', defined( 'PANTHEON_HOSTNAME' ) ? PANTHEON_HOSTNAME : $_SERVER['HTTP_HOST'] );
Config::define( 'PATH_CURRENT_SITE', '/' );
Config::define( 'SITE_ID_CURRENT_SITE', 1 );
Config::define( 'BLOG_ID_CURRENT_SITE', 1 );
Config::define( 'WP_ALLOW_MULTISITE', env( 'WP_ALLOW_MULTISITE' ) ?: true );

/**
* Custom Settings
*/
Config::define( 'AUTOMATIC_UPDATER_DISABLED', true );
// Disable the plugin and theme file editor in the admin.
Config::define( 'DISALLOW_FILE_EDIT', true );
// Disable plugin and theme updates and installation from the admin.
Config::define( 'DISALLOW_FILE_MODS', true );
// Limit the number of post revisions that Wordpress stores (true (default WP): store every revision).
Config::define( 'WP_POST_REVISIONS', env( 'WP_POST_REVISIONS' ) ?? true );

/**
* Debugging Settings
*/
if ( ( isset( $_ENV['PANTHEON_ENVIRONMENT'] ) && $_ENV['PANTHEON_ENVIRONMENT'] === 'dev' ) || isset( $_ENV['LANDO'] ) ) {
Config::define( 'WP_DEBUG_DISPLAY', true );
Config::define( 'WP_DEBUG_LOG', true );
Config::define( 'SCRIPT_DEBUG', true );
ini_set( 'display_errors', '1' );
} else {
Config::define( 'WP_DEBUG_DISPLAY', false );
Config::define( 'WP_DEBUG_LOG', false );
Config::define( 'SCRIPT_DEBUG', false );
ini_set( 'display_errors', '0' );
}

/**
* Allow WordPress to detect HTTPS when used behind a reverse proxy or a load balancer
* See https://codex.wordpress.org/Function_Reference/is_ssl#Notes
*/
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}

$env_config = __DIR__ . '/environments/' . WP_ENV . '.php';

if ( file_exists( $env_config ) ) {
require_once $env_config;
}

Config::apply();

/**
* Bootstrap WordPress
*/
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', $webroot_dir . '/wp/' );
}
19 changes: 16 additions & 3 deletions .github/tests/wpcm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test, expect } from "@playwright/test";

const exampleArticle = "Hello world!";
const siteTitle = "WPCM Playwright Tests";
const siteTitle = process.env.SITE_NAME || "WPCM Playwright Tests";
const siteUrl = process.env.SITE_URL || "https://dev-wpcm-playwright-tests.pantheonsite.io";

test("homepage loads and contains example content", async ({ page }) => {
Expand All @@ -11,7 +11,11 @@ test("homepage loads and contains example content", async ({ page }) => {
});

test("WP REST API is accessible", async ({ request }) => {
const apiRoot = await request.get(`${siteUrl}/wp-json`);
let apiRoot = await request.get(`${siteUrl}/wp-json`);
// If the api endpoint isn't /wp-json, it should be /wp/wp-json. This will probably be the case for main sites on subdirectory multisites.
if (!apiRoot.ok()) {
apiRoot = await request.get(`${siteUrl}/wp/wp-json`);
}
expect(apiRoot.ok()).toBeTruthy();
});

Expand All @@ -37,6 +41,15 @@ test("validate core resource URLs", async ({ request }) => {
});

test("graphql is able to access hello world post", async ({ request }) => {
let graphqlEndpoint = `${siteUrl}/wp/graphql`;
let apiRoot = await request.get(`${siteUrl}/wp/graphql`);
// If the above request doesn't resolve, it's because we're on a subsite where the path is ${siteUrl}/graphql -- similar to the rest api.
if (!apiRoot.ok()) {
graphqlEndpoint = `${siteUrl}/graphql`;
apiRoot = await request.get(`${siteUrl}/graphql`);
}

expect(apiRoot.ok()).toBeTruthy();
const query = `
query {
posts(where: { search: "${exampleArticle}" }) {
Expand All @@ -49,7 +62,7 @@ test("graphql is able to access hello world post", async ({ request }) => {
}
`;

const response = await request.post(`${siteUrl}/wp/graphql`, {
const response = await request.post(graphqlEndpoint, {
data: {
query: query
},
Expand Down
Loading

0 comments on commit 03c8f04

Please sign in to comment.