wp-cli-tests icon indicating copy to clipboard operation
wp-cli-tests copied to clipboard

Mock HTTP requests

Open BrianHenryIE opened this issue 1 year ago • 3 comments

Feature Request

Describe your use case and the problem you are facing

When writing my own CLI commands, they sometimes perform HTTP requests. E.g. I'm currently working with a software licence server, I want a CLI command to activate the licence, but I don't want to use a real licence server which would decrement the available licence activations and return different responses when the test is re-run.

Maybe WP CLI already has this utility, but I didn't see it.

Describe the solution you'd like

Filter pre_http_request by creating an mu-plugin for the test case which loads a PHP file containing the mocked response.

Add this to GivenStepDefinitions.php


	/**
	 * @Given /^a request to (.*?) responds? with (.*)$/
	 */
	public function given_a_request_to_a_url_respond_with_file( $url_substring_pattern, $remote_request_response_file ) {

		$project_dir = realpath( self::get_vendor_dir() . '/../' );

		switch ( true ) {
			case is_file( $remote_request_response_file ):
				$response_file = realpath( $remote_request_response_file );
				break;
			case is_file( ltrim( $remote_request_response_file, './' ) ):
				$response_file = realpath( ltrim( $remote_request_response_file, './' ) );
				break;
			case is_file( $project_dir . '/' . $remote_request_response_file ):
				$response_file = $project_dir . '/' . $remote_request_response_file;
				break;
			default:
				WP_CLI::error( "File not found: {$remote_request_response_file}" );
		}

		if ( substr( $url_substring_pattern, 0, 1 ) !== substr( $url_substring_pattern, -1 ) ) {
			$url_substring_pattern = '/' . preg_quote( $url_substring_pattern, '/' ) . '/';
		}

		$mu_plugin_name = basename( $remote_request_response_file );

		$mu_php = <<<MU_PHP
<?php
/**
 * Plugin Name: $mu_plugin_name
 * Description: Mock a response for a remote request matching `$url_substring_pattern`.
 */
 
/**
 * Filter the HTTP request to return a mock response.
 *
 * @hooked pre_http_request
 * @see \WP_Http::request()
 * 
 * @param false|array \$pre
 * @param array \$parsed_args
 * @param string \$url The request URL.
 * 
 * @return false|array{headers:array,body:string,response:array{code:int|false,message:bool|string},cookies:array,http_response:null|array}
 */
add_filter( 'pre_http_request', function( \$pre, \$parsed_args, \$url ) { 
	if ( 1 !== preg_match( '$url_substring_pattern', \$url ) ) {
		return \$pre;
	}

	return include '$response_file';
}, 10, 3 );
MU_PHP;

		file_put_contents(
			$this->variables['RUN_DIR'] . '/wp-content/mu-plugins/' . $mu_plugin_name, 
			$mu_php 
		);
	}

And a feature would look like:

  Scenario: licence set with activate flag
    Given a WP install
    Given a plugin located at ./test-plugin

    Given a request to wp-json/slswc/v1/activate? responds with tests/_data/features/activate-success.php

    When I run `wp test-plugin licence set-key abcdefghijklmnopqrstuvwxyzn --activate`
    Then STDERR should be empty
    And STDOUT should contain:
      """
      Success: active
      """

This could be generalised to almost every filter, so maybe I missed it because I was looking for a http mock.

I need to write tests on that switch statement.

BrianHenryIE avatar Jun 22 '24 18:06 BrianHenryIE