A WordPress functional testing module 03

Finally a first working version of a WordPress functional testing module.

What is this about?

I’m working to create a real functional test module for WordPress to be used with Codeception.
Mainstream frameworks like Laravel, Symfony, Zend and so on all have one.
While many will refuse the idea that WordPress is a framework proper I think no one could deny it being mainstream.
Plus that’s the big missing piece in the wp-browser Codeception modules library and it bugged me for a while.

Where the difficulty lies

The central point of a functional test is to skip the web server requirement to run.
In WordPress terms GET, POST, PUT and DELETE requests will not be routed from an Apache or Ngnix to the index.php file but the file will be hit directly from the tests.
A first big advantage is speed and a second one is being able to test the back-end handling of HTTP requests in a level that’s above integration and below acceptance.
To make a practical example this is the kind of test to use to test how a REST request is handled.
For a framework to be easily testable functionally there are some requirements:

  • it should not pollute the global space with global variables and constants
  • it should not rely on those to keep track of its state
  • it should be able to handle more than one request per run

WordPress lacks all of the characteristics above.
I could do this with a modern framework:

  • load the framework in the test variable scope
  • hit a routing element of the framework with a request
  • check the response
  • hit another routing element of the framework with another request
  • check the response
  • and so on…

But I could not do this in WordPress due to its reliance on constants and globals: there the difficulty lies.
So this required an alteration of the flow above:

  • hit a routing element of the framework with a request
    • create a process isolated from the one running the tests
      • load the framework in the separated process variable scope
      • process the request
      • return the request to the test
  • check the response
  • hit another routing element of the framework with another request
    • create a process isolated from the one running the tests
      • load the framework in the separated process variable scope
      • process the request
      • return the request to the test
  • check the response
  • and so on…

That proved to be challenging for me.

A first version

After some struggle I was able to put together a first version of a functional test WordPress module and be able to run the following tests successfully:

<?php

/**
 * Class FrontendAccessCest
 */
class FrontendAccessCest
{
    /**
     * @test
     * it should be able to navigate to main page
     */
    public function it_should_be_able_to_navigate_to_main_page(WpmoduleTester $I)
    {
        $I->amOnPage('/');
    }

    /**
     * @test
     * it should be able to insert a post in the database and see it on the homepage
     */
    public function it_should_be_able_to_insert_a_post_in_the_database_and_see_it_on_the_homepage(WpmoduleTester $I)
    {
        $I->havePostInDatabase(['post_type' => 'post', 'post_title' => 'A post', 'post_status' => 'publish']);
        $I->amOnPage('/');
        $I->see('A post');
    }

    /**
     * @test
     * it should clean the database between tests
     */
    public function it_should_clean_the_database_between_tests(WpmoduleTester $I)
    {
        $I->amOnPage('/');
        $I->dontSee('A post');
    }
}

The module is meant to be used together with the WPDb one to handle database cleanup operations and offer factory methods like the havePostInDatabase one used in the tests.
Assuming a local WordPress installation will be served from the /var/www/wp folder on the http://wp.dev address a sample configuration could be the one below:

class_name: WpmoduleTester
modules:
    enabled:
        - \Helper\Wpmodule
        - WordPress:
            wpRootFolder: "/Users/Luca/Sites/wp"
            adminUsername: 'admin'
            adminPassword: 'admin'
        - WPDb:
            dsn: 'mysql:host=127.0.0.1;dbname=wp'
            user: 'root'
            password: 'root'
            dump: 'tests/_data/dump.sql'
            reconnect: false
            url: 'http://wp.dev'
            tablePrefix: 'wp_'

Note that the url parameter required by the WPDb module has nothing to do with a web server and all to do with WordPress database stored URLs.

Next

Now that the road is open I will extend the module to be able to hit the admin, AJAX and cron areas of WordPress and be able to make real POST, PUT and DELETE requests using convenient methods.