10up / wp_mock

WordPress API Mocking Framework
https://wp-mock.gitbook.io
Other
676 stars 70 forks source link

How to Mock wp_send_json_error() #205

Closed DevWael closed 1 year ago

DevWael commented 1 year ago

I'm using wp_send_json_error() after failing to verify the nonce on a function to send an error to the browser and stop the execution. I tried to mock this function using the following:

\WP_Mock::echoFunction('wp_send_json_error', [
      'times' => 1,
      'return' => 'Failed to pass security check',
]);

What I need is to know how to stop the execution after running the mocked function and echo a text, so I may run expectOutputString to check for the output.

unfulvio-godaddy commented 1 year ago

Hi @DevWael could you paste a snippet of the code under test? And maybe the test you have written for it?

Thank you

DevWael commented 1 year ago

Hi @unfulvio-godaddy Thanks for your reply. I was building a function that do some stuff based on an AJAX request and then reply to the browser with wp_send_json_error() or wp_send_json_success() depending on the needed result.

The function looks like this


public function userData():void
    {
        //... nonce checking.
        // check if the request has user id.
        if(!isset($_GET['user_id'])){
            wp_send_json_error('user id is required!');
        }

        $userId = $_GET['user_id'];
        //the logic goes .....
    }

Then, after some research, I have been able to solve my problem by creating a separate function that checks for the user and throws an exception if the user ID is not provided.

The code is refactored to the following:

    public function userId(): int
    {
        if(!isset($_GET['user_id'])){
            throw new \Exception('user id is required!');
        }
        // verify the user id is valid and return int user id
        return $_GET['user_id'];
    }

    public function userData():void
    {
        try {
            //... nonce checking.
            // check if the request has user id.
            $userId = $this->userId();
            //the logic goes .....
        } catch (\Throwable $exception){
            wp_send_json_error($exception->getMessage());
        }
    }

That way, I have been able to stop the execution without the need of the wp_send_json_* functions. Actually, we need to test our code not the WordPress code, so if these regards to a WordPress, then consider it working perfect and don't test it. Just test when you need to stop the execution and leave the rest to WordPress.

BrianHenryIE commented 1 year ago
$sut = new AJAX( $api, $logger );

\WP_Mock::userFunction(
  'check_ajax_referer',
  array(
    'return' => false,
  )
);

\WP_Mock::userFunction(
  'wp_send_json_error',
  array(
    'args'   => array( \WP_Mock\Functions::type( 'array' ), \WP_Mock\Functions::type( 'int' ) ),
    'times'  => 1,
    'return' => function() {
      throw new \Exception();
    },
  )
);

try {
  $sut->get_order_details();
} catch ( \Exception $e ) {}

You can do it by throwing and catching exceptions just in the test.

DevWael commented 1 year ago

Yes @BrianHenryIE, exactly that's what I was looking for, and it's nearly what I'm thinking about. It's just my first beginnings with the unit testing, and I'm still learning. Thanks for the code. Hope it helps someone who is searching for this in the future.

unfulvio-godaddy commented 1 year ago

Thanks to @BrianHenryIE 😄 who posted the answer above before I could reply - I don't want to steal the credit here 😉

I will close this issue now, thank you both for bringing this up.

We plan to revamp the docs and managed to get a community plan for GitBook tied to WP_Mock. I'm a bit busy with my main work but hope to get back into WP_Mock with that in mind.