A WordPress functional testing module 05

Putting the functional tests module for WordPress to the test.

A demo plugin

I’ve referenced the “I’d like this” demo plugin in the Codeception for WordPress documentation as it contains at least one example of each test type support offered by wp-browser.
It currently also sports the WPBrowser and WPDb modules as the modules used for “functional” tests and that’s quite inaccurate.
Having reached a good point in the development of a WordPress specific functional module I wanted to test it “on the field”.

Configuring the module

The first functional test case I’ve tackled is the one dedicated to the front-end AJAX submission of “votes”.
The plugin is leveraging the REST API infrastructure introduced in WordPress 4.4 to define a REST route that will create and attach comments to a post containing the [idlikethis] shortcode.
I’ve updated the functional suite configuration file to match the new WordPress module requirements:

# Codeception Test Suite Configuration

# suite for WordPress functional tests.
# Emulate web requests and make application process them.
class_name: FunctionalTester
modules:
    enabled:
        - WPDb:
            dsn: 'mysql:host=127.0.0.1;dbname=wp'
            user: root
            password: root
            dump: tests/_data/dump.sql
            populate: true
            cleanup: true
            url: 'http://wp.dev'
            tablePrefix: wp_
        - WordPress:
            depends: WPDb
            wpRootFolder: "/Users/Luca/Sites/wp"
            adminUsername: 'admin'
            adminPassword: 'admin'
        - \Helper\Functional

The module requires the WPDb module to work but beside that there is nothing particular.

Testing light REST interactions

I’ve modified the original test case interactions to use the new methods and move from incomplete or wrong requests that should have no effects on the server to a complete and well formed interaction.

<?php

namespace rest;

class ButtonClickPostRequestCest {

    /**
     * @test
     * it should not insert any comment if post ID is missing from POST request
     */
    public function it_should_not_insert_any_comment_if_post_id_is_missing_from_post_request( \FunctionalTester $I ) {
        $I->amOnPage( '/' );

        $wp_rest_nonce = $I->grabValueFrom( 'input[name="rest_nonce"]' );
        $I->haveHttpHeader( 'X-WP-Nonce', $wp_rest_nonce );

        $I->sendAjaxPostRequest( '/wp-json/idlikethis/v1/button-click', [
            'content' => 'Some content'
        ] );

        $I->dontSeeCommentInDatabase( [ 'comment_content' => 'Some content' ] );
    }

    /**
     * @test
     * it should not insert any comment if post ID is not a valid post ID
     */
    public function it_should_not_insert_any_comment_if_post_id_is_not_a_valid_post_id( \FunctionalTester $I ) {
        $I->amOnPage( '/' );

        $wp_rest_nonce = $I->grabValueFrom( 'input[name="rest_nonce"]' );
        $I->haveHttpHeader( 'X-WP-Nonce', $wp_rest_nonce );

        $I->sendAjaxPostRequest( '/wp-json/idlikethis/v1/button-click', [
            'content' => 'Some content',
            'post_id' => 2233
        ] );

        $I->dontSeeCommentInDatabase( [ 'comment_content' => 'Some content' ] );
    }

    /**
     * @test
     * it should not insert any comment if content is missing from POST request
     */
    public function it_should_not_insert_any_comment_if_content_is_missing_from_post_request( \FunctionalTester $I ) {
        $post_id = $I->havePostInDatabase( [ 'post_title' => 'Some post' ] );

        $I->amOnPage( '/' );

        $wp_rest_nonce = $I->grabValueFrom( 'input[name="rest_nonce"]' );
        $I->haveHttpHeader( 'X-WP-Nonce', $wp_rest_nonce );

        $I->sendAjaxPostRequest( '/wp-json/idlikethis/v1/button-click', [
            'post_id' => $post_id
        ] );

        $I->dontSeeCommentInDatabase( [ 'comment_content' => 'Some content' ] );
    }

    /**
     * @test
     * it should insert a comment when hitting the endpoint with valid params
     */
    public function it_should_insert_a_comment_when_hitting_the_endpoint_with_valid_params( \FunctionalTester $I ) {
        $post_id = $I->havePostInDatabase( [ 'post_title' => 'Some post' ] );

        $I->amOnPage( '/' );

        $wp_rest_nonce = $I->grabValueFrom( 'input[name="rest_nonce"]' );
        $I->haveHttpHeader( 'X-WP-Nonce', $wp_rest_nonce );

        $I->sendAjaxPostRequest( '/wp-json/idlikethis/v1/button-click', [
            'post_id' => $post_id,
            'content' => 'Some Content'
        ] );

        $I->seeResponseCodeIs(200);
        $I->seeCommentInDatabase( [ 'comment_post_ID' => $post_id ] );
    }
}

This REST endpoint does not require the user to be authenticated so any test method will simulate the default visitor user, the one with an ID of 0.
Worth noting in the test cases above is that I’m getting the wp_rest action nonce from the page to send it along the request: in this specific case the presence of the X-WP-Nonce header makes no difference but I wanted to simulate the JavaScript workflow as closely as possible.

Next

I will move to the administration area to test the new module authentication handling.

I appreciate your input