Make WordPress Core

Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#51061 closed defect (bug) (invalid)

In WordPress 5.5 the rest_api_init action doesn't work in PHPUnit tests

Reported by: skarabeq's profile skarabeq Owned by:
Milestone: Priority: normal
Severity: normal Version: 5.5
Component: REST API Keywords:
Focuses: Cc:

Description

I have updated to the new WordPress 5.5, but unfortunately, my PHPUnit tests are failed.

I have the following code in functions.php file:

<?php

function example_route()
{
    register_rest_route('dummy', 'example/url',
        [
            [
                'methods'  => 'POST',
                'callback' => function($request) {
                    return ['url' => $request['url']];
                }
            ],
            'schema' => null,
        ]
    );
}
add_action( 'rest_api_init', 'example_route' );

I have tested the endpoint dummy/example/url with PostMan and it works. I have received the following response:

{
    "url": "http://example.org/dummy-page"
}

But when I tried to test this endpoint via PHPUnit tests it doesn't work. I have the following code in PHPUnit tests:

<?php


namespace TestCasesTheme;

/**
 * Class TestCasesTheme\ThemeTestsExampleUrl
 *
 * Class ThemeTestsExampleUrl
 * @package TestCasesTheme
 */
class ThemeTestsExampleUrl extends \WP_UnitTestCase
{
    /**
     * Test REST Server.
     *
     * @var \WP_REST_Server
     */
    private $server;

    /**
     * Name of the router.
     *
     * @var string $route_name
     */
    private $route_name = '/dummy/example/url';

    /**
     * Initialize WP API rest.
     */
    public function setUp()
    {
        parent::setUp();

        global $wp_rest_server;

        $wp_rest_server = new \WP_REST_Server;
        $this->server   = $wp_rest_server;

        do_action('rest_api_init');
    }

    /**
     * Destruction API WP rest server.
     */
    public function tearDown()
    {
        parent::tearDown();

        global $wp_rest_server;
        $wp_rest_server = null;
    }

    /**
     * Test GetPostByUrlModel /dummy/example/url.
     *
     * @return string
     */
    public function testExampleUrl()
    {
        $response = $this->get_response('http://example.org/url');
        $this->assertEquals(
            200,
            $response->get_status()
        );
    }

    /**
     * Get the API response.
     *
     * @param string $url
     * @return mixed
     */
    private function get_response($url)
    {
        $response = $this->create_request(
            $this->route_name,
            'POST',
            ['url' => $url]
        );

        return $response;
    }

    /**
     * Create API request.
     *
     * @param string $route_name
     * @param string $method
     * @param array $parameters
     * @return mixed
     */
    private function create_request($route_name, $method = 'POST', $parameters = [])
    {
        $request = new \WP_REST_Request($method,$route_name);

        if (count($parameters) > 0) {
            foreach ($parameters as $parameter => $value) {
                $request->set_param($parameter, $value);
            }
        }

        return $this->server->dispatch($request);
    }
}

In phpunit-boostrap.php I have the following code:

<?php
/**
 * PHPUnit bootstrap file
 *
 * @package TestCasesEmerchantpay3
 */

$GLOBALS['wp_tests_options'] = [
    'active_plugins' => [],
];
$_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';

function _register_theme()
{
    if (!session_id()) {
        session_start();
    }

    $theme_dir     = dirname(dirname(__FILE__));
    $current_theme = basename($theme_dir);

    register_theme_directory(dirname($theme_dir));

    add_filter('pre_option_template', function () use ($current_theme) {
        return $current_theme;
    });
    add_filter('pre_option_stylesheet', function () use ($current_theme) {
        return $current_theme;
    });
    update_option('permalink_structure', '/%category%/%postname%/');
}

tests_add_filter('muplugins_loaded', '_register_theme');

// Start up the WP testing environment.
require $_tests_dir . '/includes/bootstrap.php';

I have tested it with PHPUnit 5.7.27 and PHPUnit 6.5.14, but it doesn't work. I have the following error:

Installing...
Running as single site... To run multisite, use -c tests/phpunit/multisite.xml

Not running ajax tests. To execute these, use --group ajax.
Not running ms-files tests. To execute these, use --group ms-files.
Not running external-http tests. To execute these, use --group external-http.
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 1.32 seconds, Memory: 30.00MB

There was 1 failure:

1) TestCasesTheme\ThemeTestsExampleUrl::testExampleUrl
Unexpected incorrect usage notice for register_rest_route
Failed asserting that an array is empty.

/private/tmp/wordpress-tests-lib/includes/abstract-testcase.php:507
/private/tmp/wordpress-tests-lib/includes/abstract-testcase.php:519

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

This problem looks like the problem reported in this ticket #50366, but it is not the same, just the error message is the same.
One more thing, I have tested it with WordPress 5.4.2 version and it works well with the same code from above.
It is tested without plugins. I have tested it only with one registered route and one test suite.

Change History (2)

#1 @swissspidy
3 years ago

  • Component changed from General to REST API
  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Severity changed from major to normal
  • Status changed from new to closed

I think you need to add a permission_callback when registering your route.

That's required since 5.5 and will cause a warning. That's why you get Unexpected incorrect usage notice for register_rest_route

See https://make.wordpress.org/core/2020/07/22/rest-api-changes-in-wordpress-5-5/ for details.

#2 @skarabeq
3 years ago

@swissspidy, Thank you! It works as expected now.

Note: See TracTickets for help on using tickets.