Build/Test Tools: Add the e2e tests setup.

- Adds a local environment based on docker
 - Adds the e2e tests setup
 - Adds a "Hello World" e2e test to serve as a template

Props gziolo, herregroen, mcsf.
Fixes #45165.


git-svn-id: https://develop.svn.wordpress.org/trunk@45570 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Riad Benguella 2019-06-27 11:26:58 +00:00
parent 3202f9f37e
commit 42a8715471
13 changed files with 11617 additions and 5164 deletions

View File

@ -12,6 +12,8 @@ env:
- WP_TRAVISCI=travis:phpunit
matrix:
include:
- php: 7.2
env: WP_TRAVISCI=e2e
- php: 7.2
env: WP_TRAVISCI=travis:format
- php: 7.1
@ -103,7 +105,15 @@ before_script:
- git --version
- svn --version
- locale -a
script: npm run grunt $WP_TRAVISCI
script:
- |
if [[ "$WP_TRAVISCI" == "e2e" ]]; then
npm run env:start
npm run env:reset-site
npm run test:e2e
else
npm run grunt $WP_TRAVISCI
fi
after_script:
- |
if [[ "$WP_TEST_REPORTER" == "true" ]]; then

16209
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,11 +13,16 @@
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"devDependencies": {
"@wordpress/babel-preset-default": "4.3.0",
"@wordpress/custom-templated-path-webpack-plugin": "1.2.0",
"@wordpress/e2e-test-utils": "2.1.0",
"@wordpress/library-export-default-webpack-plugin": "1.1.0",
"@wordpress/scripts": "3.3.0",
"autoprefixer": "9.4.7",
"babel-jest": "24.8.0",
"check-node-version": "3.2.0",
"copy-webpack-plugin": "^4.6.0",
"core-js": "3.1.4",
"cssnano": "4.1.8",
"grunt": "~1.0.3",
"grunt-banner": "^0.6.0",
@ -117,6 +122,9 @@
"dev": "grunt build --dev",
"test": "grunt test",
"watch": "grunt watch",
"grunt": "grunt"
"grunt": "grunt",
"env:start": "./tools/local-env/start.sh",
"env:reset-site": "./tools/local-env/install-wordpress.sh --reset-site",
"test:e2e": "wp-scripts test-e2e --config tests/e2e/jest.config.js"
}
}

View File

@ -0,0 +1,8 @@
/**
* External dependencies
*/
const babelJest = require( 'babel-jest' );
module.exports = babelJest.createTransformer( {
presets: [ '@wordpress/babel-preset-default' ],
} );

136
tests/e2e/config/bootstrap.js vendored Normal file
View File

@ -0,0 +1,136 @@
import { get } from 'lodash';
import {
clearLocalStorage,
enablePageDialogAccept,
setBrowserViewport,
} from '@wordpress/e2e-test-utils';
/**
* Environment variables
*/
const { PUPPETEER_TIMEOUT } = process.env;
/**
* Set of console logging types observed to protect against unexpected yet
* handled (i.e. not catastrophic) errors or warnings. Each key corresponds
* to the Puppeteer ConsoleMessage type, its value the corresponding function
* on the console global object.
*
* @type {Object<string,string>}
*/
const OBSERVED_CONSOLE_MESSAGE_TYPES = {
warning: 'warn',
error: 'error',
};
/**
* Array of page event tuples of [ eventName, handler ].
*
* @type {Array}
*/
const pageEvents = [];
// The Jest timeout is increased because these tests are a bit slow
jest.setTimeout( PUPPETEER_TIMEOUT || 100000 );
/**
* Adds an event listener to the page to handle additions of page event
* handlers, to assure that they are removed at test teardown.
*/
function capturePageEventsForTearDown() {
page.on( 'newListener', ( eventName, listener ) => {
pageEvents.push( [ eventName, listener ] );
} );
}
/**
* Removes all bound page event handlers.
*/
function removePageEvents() {
pageEvents.forEach( ( [ eventName, handler ] ) => {
page.removeListener( eventName, handler );
} );
}
/**
* Adds a page event handler to emit uncaught exception to process if one of
* the observed console logging types is encountered.
*/
function observeConsoleLogging() {
page.on( 'console', ( message ) => {
const type = message.type();
if ( ! OBSERVED_CONSOLE_MESSAGE_TYPES.hasOwnProperty( type ) ) {
return;
}
let text = message.text();
// An exception is made for _blanket_ deprecation warnings: Those
// which log regardless of whether a deprecated feature is in use.
if ( text.includes( 'This is a global warning' ) ) {
return;
}
// Viewing posts on the front end can result in this error, which
// has nothing to do with Gutenberg.
if ( text.includes( 'net::ERR_UNKNOWN_URL_SCHEME' ) ) {
return;
}
// A bug present in WordPress 5.2 will produce console warnings when
// loading the Dashicons font. These can be safely ignored, as they do
// not otherwise regress on application behavior. This logic should be
// removed once the associated ticket has been closed.
//
// See: https://core.trac.wordpress.org/ticket/47183
if (
text.startsWith( 'Failed to decode downloaded font:' ) ||
text.startsWith( 'OTS parsing error:' )
) {
return;
}
const logFunction = OBSERVED_CONSOLE_MESSAGE_TYPES[ type ];
// As of Puppeteer 1.6.1, `message.text()` wrongly returns an object of
// type JSHandle for error logging, instead of the expected string.
//
// See: https://github.com/GoogleChrome/puppeteer/issues/3397
//
// The recommendation there to asynchronously resolve the error value
// upon a console event may be prone to a race condition with the test
// completion, leaving a possibility of an error not being surfaced
// correctly. Instead, the logic here synchronously inspects the
// internal object shape of the JSHandle to find the error text. If it
// cannot be found, the default text value is used instead.
text = get( message.args(), [ 0, '_remoteObject', 'description' ], text );
// Disable reason: We intentionally bubble up the console message
// which, unless the test explicitly anticipates the logging via
// @wordpress/jest-console matchers, will cause the intended test
// failure.
// eslint-disable-next-line no-console
console[ logFunction ]( text );
} );
}
// Before every test suite run, delete all content created by the test. This ensures
// other posts/comments/etc. aren't dirtying tests and tests don't depend on
// each other's side-effects.
beforeAll( async () => {
capturePageEventsForTearDown();
enablePageDialogAccept();
observeConsoleLogging();
await setBrowserViewport( 'large' );
} );
afterEach( async () => {
await clearLocalStorage();
await setBrowserViewport( 'large' );
} );
afterAll( () => {
removePageEvents();
} );

23
tests/e2e/jest.config.js Normal file
View File

@ -0,0 +1,23 @@
const path = require( 'path' );
const jestE2EConfig = {
preset: 'jest-puppeteer',
setupFilesAfterEnv: [
'<rootDir>/config/bootstrap.js',
],
testMatch: [
'<rootDir>/specs/**/__tests__/**/*.js',
'<rootDir>/specs/**/?(*.)(spec|test).js',
'<rootDir>/specs/**/test/*.js',
],
transform: {
'^.+\\.[jt]sx?$': path.join( __dirname, 'babel-transform' ),
},
transformIgnorePatterns: [
'node_modules',
'scripts/config/puppeteer.config.js',
],
};
module.exports = jestE2EConfig;

View File

@ -0,0 +1,11 @@
import { visitAdminPage } from '@wordpress/e2e-test-utils';
describe( 'Hello World', () => {
it( 'Should load properly', async () => {
await visitAdminPage( '/' );
const title = await page.$x(
'//h2[contains(text(), "Welcome to WordPress!")]'
);
expect( title ).not.toBeNull();
} );
} );

View File

@ -0,0 +1,41 @@
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
ports:
- 8889:80
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: example
ABSPATH: /usr/src/wordpress/
WORDPRESS_DEBUG: 1
WORDPRESS_CONFIG_EXTRA: |
define( 'SCRIPT_DEBUG', true );
volumes:
- wordpress_data:/var/www/html
- ../../build/:/var/www/html/
depends_on:
- mysql
cli:
image: wordpress:cli
restart: always
user: xfs
volumes:
- wordpress_data:/var/www/html
- ../../build/:/var/www/html/
depends_on:
- mysql
- wordpress
mysql:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: wordpress_test
volumes:
wordpress_data:

134
tools/local-env/includes.sh Normal file
View File

@ -0,0 +1,134 @@
#!/bin/bash
##
# Ask a Yes/No question, and way for a reply.
#
# This is a general-purpose function to ask Yes/No questions in Bash, either with or without a default
# answer. It keeps repeating the question until it gets a valid answer.
#
# @param {string} prompt The question to ask the user.
# @param {string} [default] Optional. "Y" or "N", for the default option to use if none is entered.
# @param {int} [timeout] Optional. The number of seconds to wait before using the default option.
#
# @returns {bool} true if the user replies Yes, false if the user replies No.
##
ask() {
# Source: https://djm.me/ask
local timeout endtime timediff prompt default reply
while true; do
timeout="${3:-}"
if [ "${2:-}" = "Y" ]; then
prompt="Y/n"
default=Y
elif [ "${2:-}" = "N" ]; then
prompt="y/N"
default=N
else
prompt="y/n"
default=
timeout=
fi
if [ -z "$timeout" ]; then
# Ask the question (not using "read -p" as it uses stderr not stdout)
echo -en "$1 [$prompt] "
# Read the answer (use /dev/tty in case stdin is redirected from somewhere else)
read reply </dev/tty
else
endtime=$((`date +%s` + $timeout));
while [ "$endtime" -ge `date +%s` ]; do
timediff=$(($endtime - `date +%s`))
echo -en "\r$1 [$prompt] (Default $default in ${timediff}s) "
read -t 1 reply </dev/tty
if [ -n "$reply" ]; then
break
fi
done
fi
# Default?
if [ -z "$reply" ]; then
reply=$default
fi
# Check if the reply is valid
case "$reply" in
Y*|y*) return 0 ;;
N*|n*) return 1 ;;
esac
done
}
##
# Download from a remote source.
#
# Checks for the existence of curl and wget, then downloads the remote file using the first available option.
#
# @param {string} remote The remote file to download.
# @param {string} [local] Optional. The local filename to use. If it isn't passed, STDOUT is used.
#
# @return {bool} Whether the download succeeded or not.
##
download() {
if command_exists "curl"; then
curl -s -o "${2:--}" "$1"
elif command_exists "wget"; then
wget -nv -O "${2:--}" "$1"
fi
}
##
# Add error message formatting to a string, and echo it.
#
# @param {string} message The string to add formatting to.
##
error_message() {
echo -en "\033[31mERROR\033[0m: $1"
}
##
# Add warning message formatting to a string, and echo it.
#
# @param {string} message The string to add formatting to.
##
warning_message() {
echo -en "\033[33mWARNING\033[0m: $1"
}
##
# Add status message formatting to a string, and echo it.
#
# @param {string} message The string to add formatting to.
##
status_message() {
echo -en "\033[32mSTATUS\033[0m: $1"
}
##
# Add formatting to an action string.
#
# @param {string} message The string to add formatting to.
##
action_format() {
echo -en "\033[32m$1\033[0m"
}
##
# Check if the command exists as some sort of executable.
#
# The executable form of the command could be an alias, function, builtin, executable file or shell keyword.
#
# @param {string} command The command to check.
#
# @return {bool} Whether the command exists or not.
##
command_exists() {
type -t "$1" >/dev/null 2>&1
}

View File

@ -0,0 +1,94 @@
#!/bin/bash
NVM_VERSION=`curl -Ls -w %{url_effective} -o /dev/null https://github.com/nvm-sh/nvm/releases/latest | rev | cut -d '/' -f 1 | rev`
# Exit if any command fails
set -e
# Include useful functions
. "$(dirname "$0")/includes.sh"
# Load NVM
if [ -n "$NVM_DIR" ]; then
# The --no-use option ensures loading NVM doesn't switch the current version.
if [ -f "$NVM_DIR/nvm.sh" ]; then
. "$NVM_DIR/nvm.sh" --no-use
elif command_exists "brew" && [ -f "$(brew --prefix nvm)/nvm.sh" ]; then
# use homebrew if that's how nvm was installed
. "$(brew --prefix nvm)/nvm.sh" --no-use
fi
fi
# Change to the expected directory
cd "$(dirname "$0")/../.."
# Check if nvm is installed
if [ "$TRAVIS" != "true" ] && ! command_exists "nvm"; then
if ask "$(error_message "NVM isn't installed, would you like to download and install it automatically?")" Y; then
# The .bash_profile file needs to exist for NVM to install
if [ ! -e ~/.bash_profile ]; then
touch ~/.bash_profile
fi
echo -en $(status_message "Installing NVM..." )
download "https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" | bash >/dev/null 2>&1
echo ' done!'
echo -e $(warning_message "NVM was updated, please run this command to reload it:" )
echo -e $(warning_message "$(action_format ". \$HOME/.nvm/nvm.sh")" )
echo -e $(warning_message "After that, re-run the setup script to continue." )
else
echo -e $(error_message "")
echo -e $(error_message "Please install NVM manually, then re-run the setup script to continue.")
echo -e $(error_message "NVM installation instructions can be found here: $(action_format "https://github.com/nvm-sh/nvm")")
fi
exit 1
fi
# Check if the current nvm version is up to date.
if [ "$TRAVIS" != "true" ] && [ $NVM_VERSION != "v$(nvm --version)" ]; then
echo -en $(status_message "Updating NVM..." )
download "https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" | bash >/dev/null 2>&1
echo ' done!'
echo -e $(warning_message "NVM was updated, please run this command to reload it:" )
echo -e $(warning_message "$(action_format ". \$HOME/.nvm/nvm.sh")" )
echo -e $(warning_message "After that, re-run the setup script to continue." )
exit 1
fi
# Check if the current node version is up to date.
if [ "$TRAVIS" != "true" ] && [ "$(nvm current)" != "$(nvm version-remote --lts)" ]; then
echo -e $(warning_message "Node version does not match the latest long term support version. Please run this command to install and use it:" )
echo -e $(warning_message "$(action_format "nvm install")" )
echo -e $(warning_message "After that, re-run the setup script to continue." )
exit 1
fi
# Install/update packages
echo -e $(status_message "Installing and updating NPM packages..." )
npm install
# Make sure npm is up-to-date
npm install npm -g
# There was a bug in NPM that caused changes in package-lock.json. Handle that.
if [ "$TRAVIS" != "true" ] && ! git diff --no-ext-diff --exit-code package-lock.json >/dev/null; then
if ask "$(warning_message "Your package-lock.json changed, which may mean there's an issue with your NPM cache. Would you like to try and automatically clean it up?" )" N 10; then
rm -rf node_modules/
npm cache clean --force >/dev/null 2>&1
git checkout package-lock.json
echo -e $(status_message "Reinstalling NPM packages..." )
npm install
# Check that it's cleaned up now.
if git diff --no-ext-diff --exit-code package-lock.json >/dev/null; then
echo -e $(warning_message "Confirmed that the NPM cache is cleaned up." )
else
echo -e $(error_message "We were unable to clean the NPM cache, please manually review the changes to package-lock.json. Continuing with the setup process..." )
fi
else
echo -e $(warning_message "Please manually review the changes to package-lock.json. Continuing with the setup process..." )
fi
fi

View File

@ -0,0 +1,88 @@
#!/bin/bash
# Exit if any command fails.
set -e
# Common variables.
DOCKER_COMPOSE_FILE_OPTIONS="-f $(dirname "$0")/docker-compose.yml"
WP_DEBUG=${WP_DEBUG-true}
SCRIPT_DEBUG=${SCRIPT_DEBUG-true}
# Gutenberg script includes.
. "$(dirname "$0")/includes.sh"
# These are the containers and values for the development site.
CLI='cli'
CONTAINER='wordpress'
SITE_TITLE='WordPress Dev'
# Get the host port for the WordPress container.
HOST_PORT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS port $CONTAINER 80 | awk -F : '{printf $2}')
# Wait until the Docker containers are running and the WordPress site is
# responding to requests.
echo -en $(status_message "Attempting to connect to WordPress...")
until $(curl -L http://localhost:$HOST_PORT -so - 2>&1 | grep -q "WordPress"); do
echo -n '.'
sleep 5
done
echo ''
# If this is the test site, we reset the database so no posts/comments/etc.
# dirty up the tests.
if [ "$1" == '--reset-site' ]; then
echo -e $(status_message "Resetting test database...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI db reset --yes --quiet
fi
# Install WordPress.
echo -e $(status_message "Installing WordPress...")
# The `-u 33` flag tells Docker to run the command as a particular user and
# prevents permissions errors. See: https://github.com/WordPress/gutenberg/pull/8427#issuecomment-410232369
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core install --title="$SITE_TITLE" --admin_user=admin --admin_password=password --admin_email=test@test.com --skip-email --url=http://localhost:$HOST_PORT --quiet
if [ "$E2E_ROLE" = "author" ]; then
echo -e $(status_message "Creating an additional author user for testing...")
# Create an additional author user for testing.
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI user create author author@example.com --role=author --user_pass=authpass --quiet
# Assign the existing Hello World post to the author.
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI post update 1 --post_author=2 --quiet
fi
CURRENT_WP_VERSION=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm $CLI core version)
echo -e $(status_message "Current WordPress version: $CURRENT_WP_VERSION...")
if [ "$WP_VERSION" == "latest" ]; then
# Check for WordPress updates, to make sure we're running the very latest version.
echo -e $(status_message "Updating WordPress to the latest version...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core update --quiet
echo -e $(status_message "Updating The WordPress Database...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core update-db --quiet
fi
# If the 'wordpress' volume wasn't during the down/up earlier, but the post port has changed, we need to update it.
echo -e $(status_message "Checking the site's url...")
CURRENT_URL=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm $CLI option get siteurl)
if [ "$CURRENT_URL" != "http://localhost:$HOST_PORT" ]; then
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI option update home "http://localhost:$HOST_PORT" --quiet
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI option update siteurl "http://localhost:$HOST_PORT" --quiet
fi
# Install a dummy favicon to avoid 404 errors.
echo -e $(status_message "Installing a dummy favicon...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm $CONTAINER touch /var/www/html/favicon.ico
# Configure site constants.
echo -e $(status_message "Configuring site constants...")
WP_DEBUG_CURRENT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json WP_DEBUG)
if [ $WP_DEBUG != $WP_DEBUG_CURRENT ]; then
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI config set WP_DEBUG $WP_DEBUG --raw --type=constant --quiet
WP_DEBUG_RESULT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json WP_DEBUG)
echo -e $(status_message "WP_DEBUG: $WP_DEBUG_RESULT...")
fi
SCRIPT_DEBUG_CURRENT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json SCRIPT_DEBUG)
if [ $SCRIPT_DEBUG != $SCRIPT_DEBUG_CURRENT ]; then
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI config set SCRIPT_DEBUG $SCRIPT_DEBUG --raw --type=constant --quiet
SCRIPT_DEBUG_RESULT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json SCRIPT_DEBUG)
echo -e $(status_message "SCRIPT_DEBUG: $SCRIPT_DEBUG_RESULT...")
fi

View File

@ -0,0 +1,34 @@
#!/bin/bash
# Exit if any command fails.
set -e
# Common variables.
DOCKER_COMPOSE_FILE_OPTIONS="-f $(dirname "$0")/docker-compose.yml"
# Include useful functions.
. "$(dirname "$0")/includes.sh"
# Check that Docker is installed.
if ! command_exists "docker"; then
echo -e $(error_message "Docker doesn't seem to be installed. Please head on over to the Docker site to download it: $(action_format "https://www.docker.com/products/docker-desktop")")
exit 1
fi
# Check that Docker is running.
if ! docker info >/dev/null 2>&1; then
echo -e $(error_message "Docker isn't running. Please check that you've started your Docker app, and see it in your system tray.")
exit 1
fi
# Stop existing containers.
echo -e $(status_message "Stopping Docker containers...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS down --remove-orphans >/dev/null
# Download image updates.
echo -e $(status_message "Downloading Docker image updates...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS pull
# Launch the containers.
echo -e $(status_message "Starting Docker containers...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS up -d >/dev/null

65
tools/local-env/start.sh Normal file
View File

@ -0,0 +1,65 @@
#!/bin/bash
# Exit if any command fails
set -e
# Include useful functions
. "$(dirname "$0")/includes.sh"
# Change to the expected directory
cd "$(dirname "$0")/../../"
# Check Node and NVM are installed
. "$(dirname "$0")/install-node-nvm.sh"
# Check Docker is installed and running and launch the containers
. "$(dirname "$0")/launch-containers.sh"
# Set up WordPress Development site.
# Note: we don't bother installing the test site right now, because that's
# done on every time `npm run test-e2e` is run.
. "$(dirname "$0")/install-wordpress.sh"
! read -d '' WORDPRESS <<"EOT"
`-/+osssssssssssso+/-`
./oys+:.` `.:+syo/.
.+ys:. .:/osyyhhhhyyso/:. ./sy+.
/ys: -+ydmmmmmmmmmmmmmmmmmmdy+- :sy/
/h+` -odmmmmmmmmmmmmmmmmmmmmmmmmmmdo- `+h/
:ho` /hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmds/ `oh:
`sy. /hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmd+ .ys`
.ho `sdddhhhyhmmmdyyhhhdddddhhhyydmmmmy oh.
.h+ ``-dmmy.`` ``.ymmmmh +h.
`ho ` /mmmmmmmmmmo .dmmmmmmmms ~~ oh`
oy .h` ymmmmmmmmmm: /mmmmmmmmmy` -d. yo
.d- ymy `dmmmmmmmmmd. ymmmmmmmmmh` /my -d.
oy -mmm+ /mmmmmmmmmmy .dmmmmmmmmmy ymm- yo
h+ +mmmd- smmmmmmmmmm+ /mmmmmmmmmm- :mmm+ +h
d/ smmmmh` `dmmmmmmmmmd` smmmmmmmmm: `dmmms /d
d/ smmmmms :mmmmmmmmm+ `dmmmmmmmd. smmmms /d
h+ +mmmmmm/ smmmmmmmh + /mmmmmmmy /mmmmm+ +h
oy -mmmmmmd. `dmmmmmd- +m/ smmmmmd. .dmmmmm- yo
.d- ymmmmmmh :mmmmm+ .dmd- `dmmmm/ ymmmmmy -d.
oy .dmmmmmmo smmmh hmmmh` :mmmy +mmmmmd. yo
`ho -dmmmmmd: `dmd- ommmmms smd- .dmmmmd- oh`
.h+ -dmmmmmd` :m+ -dmmmmmm: `do hmmmmd- +h.
.ho .ymmmmmy + `hmmmmmmmd. :` ommmmy. oh.
`sy. /hmmmm+ ommmmmmmmmy -dmmh/ .ys`
:ho` /hmmd- :mmmmmmmmmmmo `hmh/ `oh:
/h+` -odh` `dmmmmmmmmmmmd: oo- `+h/
/ys: ~~ smmmmmmmmmmmmmd` :sy/
.+ys/. `/osyyhhhhyyso/:` ./sy+.
./oys+:.` `.:+syo/.
`-/+osssssssssssso+/-`
EOT
CURRENT_URL=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm cli option get siteurl)
echo -e "\nWelcome to...\n"
echo -e "\033[95m$WORDPRESS\033[0m"
# Give the user more context to what they should do next: Run the environment and start testing!
echo -e "\nOpen $(action_format "$CURRENT_URL") to get started!"
echo -e "\n\nAccess the above install using the following credentials:"
echo -e "Default username: $(action_format "admin"), password: $(action_format "password")"