Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup server side unit tests #617

Merged
merged 9 commits into from
May 5, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,63 @@
language: node_js
node_js:
- "node"
sudo: false

language:
- php
- node_js
Copy link
Member

Choose a reason for hiding this comment

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

Only a single language is supported by Travis CI, keep - php and remove - node_js


notifications:
email:
on_success: never
on_failure: change

branches:
only:
- master

Copy link
Member

Choose a reason for hiding this comment

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

The above 3 lines will need to be removed won't they if we want Travis to run against each PR?

cache:
directories:
- vendor
- $HOME/.composer/cache

matrix:
include:
- php: 7.1
env: WP_VERSION=latest
- php: 5.6
env: WP_VERSION=latest
- php: 5.2
env: WP_VERSION=latest
Copy link
Member

Choose a reason for hiding this comment

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

See https://core.trac.wordpress.org/ticket/40407 - I don't think we need such a large matrix here. We should include:

  • PHP 5.2 (minimum supported WP version)
  • PHP 5.6 (last 5.x version)
  • PHP 7.1 (latest version)

- php: 5.6
env: TRAVISCI=phpcs
- env: TRAVISCI=js
Copy link
Member

@ntwb ntwb May 4, 2017

Choose a reason for hiding this comment

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

I think this is meant to include a PHP version for this matrix job:

    - php: 7.1
      env: TRAVISCI =js

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no it's not, in this case we want to run the JS job only

Copy link
Member

Choose a reason for hiding this comment

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

You still need a "language" to form the base of the build job in the matrix I believe, each job in the matrix should have both a language for the job i.e. - php: 7.1 and its associated environment matrix -env: TRAVISCI =js

If Travis were running jobs against this PR we could take a look 😖


before_script:
- export PATH="$HOME/.composer/vendor/bin:$PATH"
- |
if [[ ! -z "$WP_VERSION" ]] ; then
bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
if [[ ${TRAVIS_PHP_VERSION:0:2} == "5." ]]; then
composer global require "phpunit/phpunit=4.8.*"
else
composer global require "phpunit/phpunit=5.7.*"
fi
fi
- |
if [[ "$TRAVISCI" == "phpcs" ]] ; then
composer global require wp-coding-standards/wpcs
phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
fi

script:
- "npm run ci"
- |
if [[ ! -z "$WP_VERSION" ]] ; then
phpunit
WP_MULTISITE=1 phpunit
fi
- |
if [[ "$TRAVISCI" == "phpcs" ]] ; then
phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php')
fi
- |
if [[ "$TRAVISCI" == "js" ]] ; then
npm run ci
fi
127 changes: 127 additions & 0 deletions bin/install-wp-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env bash

if [ $# -lt 3 ]; then
echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
exit 1
fi

DB_NAME=$1
DB_USER=$2
DB_PASS=$3
DB_HOST=${4-localhost}
WP_VERSION=${5-latest}
SKIP_DB_CREATE=${6-false}

WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}

download() {
if [ `which curl` ]; then
curl -s "$1" > "$2";
elif [ `which wget` ]; then
wget -nv -O "$2" "$1"
fi
}

if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
WP_TESTS_TAG="tags/$WP_VERSION"
elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
WP_TESTS_TAG="trunk"
else
# http serves a single offer, whereas https serves multiple. we only want one
download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
if [[ -z "$LATEST_VERSION" ]]; then
echo "Latest WordPress version could not be found"
exit 1
fi
WP_TESTS_TAG="tags/$LATEST_VERSION"
fi

set -ex

install_wp() {

if [ -d $WP_CORE_DIR ]; then
return;
fi

mkdir -p $WP_CORE_DIR

if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
mkdir -p /tmp/wordpress-nightly
download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip
unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/
mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR
else
if [ $WP_VERSION == 'latest' ]; then
local ARCHIVE_NAME='latest'
else
local ARCHIVE_NAME="wordpress-$WP_VERSION"
fi
download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz
tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
fi

download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
}

install_test_suite() {
# portable in-place argument for both GNU sed and Mac OSX sed
if [[ $(uname -s) == 'Darwin' ]]; then
local ioption='-i .bak'
else
local ioption='-i'
fi

# set up testing suite if it doesn't yet exist
if [ ! -d $WP_TESTS_DIR ]; then
# set up testing suite
mkdir -p $WP_TESTS_DIR
svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
fi

if [ ! -f wp-tests-config.php ]; then
download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
# remove all forward slashes in the end
WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
fi

}

install_db() {

if [ ${SKIP_DB_CREATE} = "true" ]; then
return 0
fi

# parse DB_HOST for port or socket references
local PARTS=(${DB_HOST//\:/ })
local DB_HOSTNAME=${PARTS[0]};
local DB_SOCK_OR_PORT=${PARTS[1]};
local EXTRA=""

if ! [ -z $DB_HOSTNAME ] ; then
if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
elif ! [ -z $DB_SOCK_OR_PORT ] ; then
EXTRA=" --socket=$DB_SOCK_OR_PORT"
elif ! [ -z $DB_HOSTNAME ] ; then
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
fi
fi

# create database
mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
}

install_wp
install_test_suite
install_db
21 changes: 18 additions & 3 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ function register_block( $slug, $settings ) {
}

if ( isset( $registered_blocks[ $slug ] ) ) {
$message = sprintf( __( 'Block "%s" is already registered.' ), $slug );
_doing_it_wrong( __FUNCTION__, $message, '0.1.0' );
return;
}

Expand All @@ -66,6 +64,23 @@ function register_block( $slug, $settings ) {
return $settings;
}

/**
* Unregisters a block.
*
* @param string slug Block slug
* @return array The previous block value, if it has been
* successfully unregistered; otherwise `null`.
*/
function unregister_block( $slug ) {
global $registered_blocks;
if ( ! isset( $registered_blocks[ $slug ] ) ) {
$message = sprintf( __( 'Block "%s" is not registered.' ), $slug );
_doing_it_wrong( __FUNCTION__, $message, '0.1.0' );
return;
}
unset( $registered_blocks[ $slug ] );
}

/**
* Extract the block attributes from the block's attributes string
*
Expand Down Expand Up @@ -99,7 +114,7 @@ function do_blocks( $content ) {
global $registered_blocks;

// Extract the blocks from the post content
$open_matcher = '/<!--\s*wp:([a-z](?:[a-z0-9\/]+)*)\s+((?:(?!-->).)*)-->.*<!--\s*\/wp:\g1\s+-->/';
$open_matcher = '/<!--\s*wp:([a-z](?:[a-z0-9\/]+)*)\s+((?:(?!-->).)*)--><!--\s*\/wp:\g1\s+-->/';
Copy link
Member

Choose a reason for hiding this comment

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

We need the .* here, don't we? Or is this intended to match only blocks with no content?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was thinking we should match only the empty blocks. see #586 (comment)

But with the HTML fallback feature, we need to capture the .* .


Reintroducing the .* breaks the unit tests because this

'<!-- wp:core/dummy value:b1 --><!-- /wp:core/dummy -->' .
'between' .
'<!-- wp:core/dummy value:b2 --><!-- /wp:core/dummy -->' .

match only one block, it takes the first and the last opening/closing tags only in consideration and all what's in between is catched by the .*. I'll take a deeper look and see if I can update the regex to change the priorities.

Copy link
Member

Choose a reason for hiding this comment

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

A non-greedy match .*? should work here. Are there any cases we need to support that don't have tests?

Copy link
Contributor Author

@youknowriad youknowriad May 4, 2017

Choose a reason for hiding this comment

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

Are there any cases we need to support that don't have tests?

We're covering everything for now I think. Oh! maybe the register the same block twice.

preg_match_all( $open_matcher, $content, $matches, PREG_OFFSET_CAPTURE );

$new_content = $content;
Expand Down
10 changes: 10 additions & 0 deletions phpcs.ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<ruleset name="WordPress Coding Standards for Plugins">
<description>Generally-applicable sniffs for WordPress plugins</description>

<rule ref="WordPress-Core" />
<rule ref="WordPress-Docs" />

<exclude-pattern>*/node_modules/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
</ruleset>
14 changes: 14 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<phpunit
bootstrap="phpunit/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite>
<directory prefix="test-" suffix=".php">./phpunit/</directory>
</testsuite>
</testsuites>
</phpunit>
25 changes: 25 additions & 0 deletions phpunit/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
/**
* PHPUnit bootstrap file
*
* @package Gutenberg
*/

$_tests_dir = getenv( 'WP_TESTS_DIR' );
if ( ! $_tests_dir ) {
$_tests_dir = '/tmp/wordpress-tests-lib';
}

// Give access to tests_add_filter() function.
require_once $_tests_dir . '/includes/functions.php';

/**
* Manually load the plugin being tested.
*/
function _manually_load_plugin() {
require dirname( dirname( __FILE__ ) ) . '/index.php';
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );

// Start up the WP testing environment.
require $_tests_dir . '/includes/bootstrap.php';
42 changes: 42 additions & 0 deletions phpunit/test-dynamic-blocks-render.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

class DynamicBlocksRenderTest extends WP_UnitTestCase {
/**
* @expectedIncorrectUsage register_block
*/
function test_invalid_non_string_slugs() {
register_block( 1, array() );
}

/**
* @expectedIncorrectUsage register_block
*/
function test_invalid_slugs_without_namespace() {
register_block( 'text', array() );
}

function render_dummy_block( $attributes ) {
return $attributes[ 'value' ];
}

function test_register_block() {
$settings = array( 'render' => [ $this, 'render_dummy_block' ] );
register_block( 'core/dummy', $settings );
$post_content =
'before' .
'<!-- wp:core/dummy value:b1 --><!-- /wp:core/dummy -->' .
'between' .
'<!-- wp:core/dummy value:b2 --><!-- /wp:core/dummy -->' .
'after';

$updated_post_content = do_blocks( $post_content );
unregister_block( 'core/dummy' );
$this->assertEquals( $updated_post_content,
'before' .
'b1' .
'between' .
'b2' .
'after'
);
}
}
27 changes: 27 additions & 0 deletions phpunit/test-registration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

class RegistrationTest extends WP_UnitTestCase {
/**
* @expectedIncorrectUsage register_block
*/
function test_invalid_non_string_slugs() {
register_block( 1, array() );
}

/**
* @expectedIncorrectUsage register_block
*/
function test_invalid_slugs_without_namespace() {
register_block( 'text', array() );
}

function test_register_block() {
$settings = array( 'icon' => 'text' );
$updated_settings = register_block( 'core/text', $settings );
$this->assertEquals( $updated_settings, array(
'icon' => 'text',
'slug' => 'core/text'
) );
unregister_block( 'core/text' );
}
}