0

I have a method that is hooked to the rest_api_init

  /**
   * Set allowed headers for the rest request
   */
  public function set_allowed_rest_headers() {

    remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );

    add_filter(
      'rest_pre_serve_request', function( $value ) {
        header( 'Access-Control-Allow-Origin: ' . esc_url_raw( 'some url pulled from options' ) );
        header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE, PATCH' );
        header( 'Access-Control-Allow-Credentials: true' );

        return $value;
      }
    );
  }

I want to test this using phpunit.

I've created a test case

<?php
/**
 * Class Test_Admin
 *
 * @package test
 */

/**
 * Class that tests the REST functionality.
 */
class Test_Rest extends WP_UnitTestCase {
  /**
   * Initial set up for the test
   */
  public function setUp() {
    parent::setUp();

    /**
     * Global $wp_rest_server variable
     *
     * @var WP_REST_Server $wp_rest_server Mock REST server.
     */
    global $wp_rest_server;

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

    do_action( 'rest_api_init' );

  }

  /**
   * Tear down after test ends
   */
  public function tearDown() {
    parent::tearDown();

    global $wp_rest_server;
    $wp_rest_server = null;

  }

  /**
   * Test if the REST API headers are set
   *
   * @since 1.1.0
   */
  public function test_allowed_rest_headers() {

    $request  = new WP_REST_Request( 'GET', '/wp/v2/posts' );
    $response = $this->server->dispatch( $request );

    $this->assertEquals( 200, $response->get_status() );

    $headers  = $request->get_headers();
    $headers2 = $response->get_headers();
    error_log( print_r( $headers, true ) );
    error_log( print_r( $headers2, true ) );
  }
}

The assertion that response is 200 is passing, but the error_log returns nothing for the request headers, and

Array
(
    [X-WP-Total] => 0
    [X-WP-TotalPages] => 0
)

For the response headers. But I'd need to test that the Access-Control-Allow-* headers are set correctly.

How to do that (besides manually setting them during the unit test)?

I've tried calling the set_allowed_rest_headers() method inside the test, but nothing.

2 Answers 2

1

The question actually has nothing specific to wordpress, but maybe it is worth answering.

There is simply no code of your own in that sample that can be/is worth testing, therefor there isn't much to unit test.

Lets look at the details. add_filter is integration with core code, remove_filter is integration with core code and header is integration with PHP core. If you remove all of those lines you are left with zero code.

Or to say it differently, the three functions mentions above are changing the global state and not your internal state, and while you might be able to construct a relevant test, in the end you are going to be testing them much more than testing your own code.

What you need here is an integration test, set a wordpress instance with your code, send an api request and inspect the result.

4
  • I meant integration test, not unit test, since this is the code from the plugin. I'm using wp-cli's scaffold.
    – dingo_d
    Jun 7, 2018 at 16:46
  • You need to decide what is it that you are testing. If you test the way the whole application is functioning than you need to do it from the outside. As I said for the specific code you showed there is basically nothing else to test, and any test oriented abstraction you might do will only result in needlessly complex code. Jun 7, 2018 at 17:02
  • What do you mean 'from the outside'? I'm using WordPress in a decoupled way. The front end app is communicating with it via REST API. I'm setting the headers for any rest requests because I need to avoid CORS issues. By setting the headers on rest_pre_serve_request I'm modifying the request. So basically I need to have an automated test proving that it works (not my requirement, clients). I know that it works because I've tested it with the frontend app. I just need to have a code coverage :/
    – dingo_d
    Jun 7, 2018 at 17:34
  • If you need to test how the plugin behaves, than the only thing is to test it from outside of wordpress. For proper test of what you need it is not enough to test that segment in isolation, because maybe that code is never included. So again the question is what is it that you want to test, if it is the end result of sending a request and getting the result than you have to do it from outside of wordpress Jun 7, 2018 at 17:54
0

If what you're indeed trying to do is to verify that the WordPress Core continues to behave correctly after future upgrades and that your hooked method is triggered and that the headers are thus set on the response, then I have a suggestion.

First, you're going to want to make sure you've some way of debugging this application. I suggest breakpoints, but it looks like you're partial to print statements. Either works, but if you use print statements, then be sure to print some dummy data to verify that you can tell the difference between an empty variable or a misconfigured logging level.

Given a debugging method, there's a few places to hook into. First, make sure that your "rest_api_init" hooked function is in fact being called. Print at the start of it and verify you see your message. Assuming you do, then the rabbit hole goes on.

In my version of WordPress, line 494 of class-wp-rest-server.php has your rest_pre_serve_request filter being triggered. Debug that you're in fact triggering that line with your test invocation -- you should be able to print before, then see your attached function fire, and then also print after.

Assuming you're hitting that line, and that your attached function is triggered, note that the rest (haha no pun intended) of that core method does not include any calls to $this->send_headers(...) so I assume at this point your headers(...) call (being core PHP code) should be working.

If not, note that just above on line 474 we see $headers = $result->get_headers(); so looking up the docs for WP_Rest_Response we see it extends WP_HTTP_Response which has the ability to set headers in the constructor and also directly with set_headers. From here, you can create a middleware for your responses which set the headers for you, in a worst-case scenario.

Further digging into the core file can help you understand why your headers(...) calls as-is do not work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.