Remote Requests

Introduction

Remote request mocks are a very common use case to test against when unit testing. Mantle gives you the ability to mock specific requests and fluently generate a response.

By default Mantle won't mock any HTTP request but will actively notify you when one is being made inside a unit test.

WARNING

This only supports requests made via the WP_Http APIopen in new window (wp_remote_request(), wp_remote_get(), wp_remote_post(), etc.)

Faking Requests

Intercept all remote requests with a specified response code and body.

$this->fake_request()
  ->with_response_code( 404 )
  ->with_body( 'test body' );

Faking Multiple Endpoints

Faking a specific endpoint, testing.com will return a 404 while github.com will return a 500.

$this->fake_request( 'https://testing.com/*' )
  ->with_response_code( 404 )
  ->with_body( 'test body' );

$this->fake_request( 'https://github.com/*' )
  ->with_response_code( 500 )
  ->with_body( 'fake body' );

You can also pass an array with a set of responses (or a callback):

use Mantle\Testing\Mock_Http_Response;

$this->fake_request(
  [
    'https://github.com/*'  => Mock_Http_Response::create()->with_body( 'github' ),
    'https://twitter.com/*' => Mock_Http_Response::create()->with_body( 'twitter' ),
  ]
);

Faking With a Callback

If you require more complicated logic to determine the response, you can use a closure that will be invoked when a request is being faked. It should return a mocked HTTP response:

$this->fake_request(
  function( string $url, array $request_args ) {
    if ( false === strpos( $url, 'alley.co' ) ) {
      return;
    }

    return Mock_Http_Response::create()
      ->with_response_code( 123 )
      ->with_body( 'alley!' );
  }
);

Faking Response Sequences

Sometimes a single URL should return a series of fake responses in a specific order. This can be accomplished via Mock_Http_Sequence to build the response sequence:

$this->fake_request(
  [
    'https://github.com/*' => Mock_Http_Sequence::create()
      ->push_status( 200 )
      ->push_status( 400 )
      ->push_status( 500 )
  ],
);

Any request made in the above example will use a response in the defined sequence. When all the responses in a sequence have been consumed, further requests will throw an exception. You can also specify a default response that will be returned when there are no responses left in the sequence:

$this->fake_request(
  [
    'https://github.com/*' => Mock_Http_Sequence::create()
      ->push( Mock_Http_Response::create()->with_json( [ 1, 2, 3 ] )
      ->push( Mock_Http_Response::create()->with_json( [ 4, 5, 6 ] )
      ->when_empty( Mock_Http_Response::create()->with_json( [ 4, 5, 6 ] )
  ],
);

Generating a Response

Mantle\Testing\Mock_Http_Response exists to help you fluently build a WordPress-style remote response.

use Mantle\Testing\Mock_Http_Response;

// 404 response.
Mock_Http_Response::create()
  ->with_response_code( 404 )
  ->with_body( 'test body' );

// JSON response.
Mock_Http_Response::create()
  ->with_json( [ 1, 2, 3 ] );

// Redirect response.
Mock_Http_Response::create()
  ->with_redirect( 'https://wordpress.org/' );

Asserting Requests

All remote requests can be asserted against, even if they're not being faked by the test case. Mantle will log if an actual remote request is being made during a unit test.

$this->assertRequestSent( 'https://alley.co/' );
$this->assertRequestNotSent( 'https://anothersite.com/' );
$this->assertNoRequestSent();
$this->assertRequestCount( int $number );

Requests can also be asserted against using a callback that is passed the Mantle\Http_Client\Request object:

use Mantle\Facade\Http;
use Mantle\Http_Client\Request;

Http::with_basic_auth( 'user', 'pass' )
  ->get( 'https://example.com/basic-auth/' );

$this->assertRequestSent( fn ( Request $request ) => $request
  ->has_header( 'Authorization', 'Basic dXNlcjpwYXNz' )
  && 'https://example.com/basic-auth/' === $request->url()
  && 'GET' === $request->method()
);

$this->assertRequestNotSent( fn ( Request $request ) => $request
  ->has_header( 'Content-Type', 'application-json' )
  && 'https://example.com/get/' === $request->url()
  && 'GET' === $request->method()
);