Skip to content

Commit

Permalink
Rework mocker to allow mocking multiple consecutive requests
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasplevy committed Aug 18, 2022
1 parent 9fa8984 commit 0af1273
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 34 deletions.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,45 @@ Add mock `$_GET` data via `$this->mockGetRequest( array( 'var' => 'value' ) );`

Add mock `$_POST` data via `$this->mockPostRequest( array( 'var' => 'value' ) );`


##### Mock HTTP request made via `wp_remote_request()`.

Before calling `wp_remote_request()` run `$this->mock_http_request( $url, $data, $fuzzy_match )` to setup the desired return of the next `wp_remote_request()`.

When `wp_remote_request()` is run, the mocker will check to see if a mock has been added for the URL, if found, it will short-circuit the HTTP request and return early (before any remote connection is made), returning the value of `$data`. Once the mock is found and returned, it will be removed from the mocker's data. If you wish to mock several consecutive URLs you can call `mock_http_request()` multiple times. The matcher will always return the *first* match. So if you wish to mock the same URL more than once, make sure setup the mocks in the order you expect them to be returned.

You can specify a full or partial URL as the `$url` parameter. If a specifying a partial URL, use `$fuzzy_match = true` to match the URL part.

```php

public function test_mock_https_request() {

// Mocks a WP REST post creation request.
$this->mock_http_request( '/wp-json/wp/v2/posts',
[
'body' => '{"id":123,"title":"Mock Title",...}',
'response' => [
'code' => 201,
],
],
true
);

$res = wp_remote_post(
rest_url( '/wp-json/wp/v2/posts' ),
[
'body' => [
'title' => 'Mock Title',
],
],
);

$this->assertEquals( 201, wp_remote_retrieve_response_code( $res ) );
$this->assertEquals( 123, json_decode( wp_remote_retrieve_response_body( $res ) )['id'] );

}


##### Utility Methods

+ Get the output of a function: `$output = $this->get_output( $callable, $args_array );`
Expand Down
66 changes: 32 additions & 34 deletions framework/traits/trait-llms-test-mock-http.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,80 +3,78 @@
* Mock HTTP requests made via `wp_remote_request()`.
*
* @since 1.5.0
* @version 1.5.0
* @version 4.0.0
*/
trait LLMS_Unit_Test_Mock_Http {

/**
* Request URL to mock.
*
* @var string
*/
protected $_url_to_mock = '';

/**
* Mock HTTP Request Return.
* Array of requests to mock.
*
* @var array
*/
protected $_mock_return = array();

/**
* Whether or not `$_url_to_mock` should be an exact or fuzzy match.
*
* @var bool
*/
protected $_fuzzy_match = false;
protected $_mock_http_requests = array();

/**
* Setup mock http request data.
*
* @since 1.5.0
* @since 4.0.0 Updated to allow mocking multiple consecutive requests.
*
* @param string $url_to_mock The URL to mock.
* @param array|obj|WP_Error $mock_return The mock data to respond with.
* @return void
*/
protected function mock_http_request( $url_to_mock, $mock_return = array(), $fuzzy = false ) {

$this->_url_to_mock = $url_to_mock;
$this->_mock_return = $mock_return;
$this->_fuzzy_match = $fuzzy;
$this->_mock_http_requests[] = array(
'url' => $url_to_mock,
'return' => $mock_return,
'fuzzy' => $fuzzy,
);

add_filter( 'pre_http_request', array( $this, '_handle_mock_http_request' ), 10, 3 );
if ( ! has_filter( 'pre_http_request', array( $this, '_handle_mock_http_request' ) ) ) {
add_filter( 'pre_http_request', array( $this, '_handle_mock_http_request' ), 10, 3 );
}

}

/**
* Mock `wp_remote_request` via the `pre_http_request`
*
* @since 1.5.0
* @since 4.0.0 Updated to allow mocking multiple consecutive requests.
*
* @link https://developer.wordpress.org/reference/hooks/pre_http_request/
*
* @param false|array|WP_Error $ret Whether to preempt the response.
* @param array $args HTTP Request args.
* @param string $url Request url.
* @param false|array|WP_Error $ret Whether to preempt the response.
* @param array $args HTTP Request args.
* @param string $url Request url.
* @return false|array|WP_Error
*/
public function _handle_mock_http_request( $ret, $args, $url ) {

// This is our mock url.
if ( ( $this->_fuzzy_match && false !== strpos( $url, $this->_url_to_mock ) ) || $url === $this->_url_to_mock ) {
// Loop through all mocked requests.
foreach ( $this->_mock_http_requests as $i => $mock_data ) {

// Return the mock return data.
$ret = $this->_mock_return;
// This is a valid URL to mock.
if ( ( $mock_data['fuzzy'] && false !== strpos( $url, $mock_data['url'] ) ) || $url === $mock_data['url'] ) {

// Reset class members.
$this->_url_to_mock = '';
$this->_mock_return = array();
$this->_fuzzy_match = false;
// Return the mock return data.
$ret = $mock_data['return'];

// Remove the filter.
remove_filter( 'pre_http_request', array( $this, '_handle_mock_http_request' ), 10 );
// Remove the request.
unset( $this->_mock_http_requests[ $i ] );
break;

}

}

// No more requests to mock.
if ( empty( $this->_mock_http_requests ) ) {
remove_filter( 'pre_http_request', array( $this, '_handle_mock_http_request' ), 10 );
}

return $ret;

}
Expand Down

0 comments on commit 0af1273

Please sign in to comment.