{"id":241,"date":"2025-01-11T12:43:32","date_gmt":"2025-01-11T12:43:32","guid":{"rendered":"https:\/\/www.mitango.app\/?p=241"},"modified":"2025-02-20T20:40:22","modified_gmt":"2025-02-20T20:40:22","slug":"wordpress-integration-test-ajax-request","status":"publish","type":"post","link":"https:\/\/www.mitango.app\/fr\/2025\/01\/11\/wordpress-integration-test-ajax-request\/","title":{"rendered":"WordPress integration test: Ajax request"},"content":{"rendered":"<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#overall-plan\">Overall plan<\/a><ul><li><a href=\"#theory-behind-testing-ajax-request\">Theory behind testing ajax request<\/a><\/li><li><a href=\"#the-example\">The example<\/a><\/li><\/ul><\/li><li><a href=\"#creating-the-testcase\">Creating the testcase<\/a><ul><li><a href=\"#creating-the-test-method\">Creating the test method<\/a><\/li><li><a href=\"#setup-the-initial-word-press-state\">Setup the initial WordPress state<\/a><\/li><li><a href=\"#initializing-the-request\">Initializing the request<\/a><\/li><li><a href=\"#sending-the-ajax-request\">Sending the Ajax request<\/a><\/li><li><a href=\"#assert-on-the-response\">Assert on the response<\/a><\/li><li><a href=\"#assert-the-final-state\">Assert the final state<\/a><\/li><li><a href=\"#overall-code\">Overall code<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n\n<p>In some occasions it is essential to use Ajax request inside your plugin.<\/p>\n\n\n\n<p>In that article we will see how it is possible to test your Ajax requests using integration tests.<\/p>\n\n\n\n<p>In case you don&#8217;t know yet how to setup integration tests on your project, you can check <a href=\"https:\/\/www.mitango.app\/fr\/2024\/03\/01\/setup-integration-tests-for-your-wordpress-plugin\/\" data-type=\"post\" data-id=\"223\">my previous article on the topic<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"overall-plan\">Overall plan<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"theory-behind-testing-ajax-request\">Theory behind testing ajax request<\/h3>\n\n\n\n<p>A test concerning an Ajax request always follow the same plan.<\/p>\n\n\n\n<p>First, we will prepare WordPress state to setup the initial state from the test.<\/p>\n\n\n\n<p>Next, we will send a request to WordPress to execute the logic we want to test.<\/p>\n\n\n\n<p>Finally, we will assert that the state we are in after the response is the one expected and for that we will assert the Ajax response is correct.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"681\" src=\"https:\/\/www.mitango.app\/app\/uploads\/2024\/11\/ajax-1024x681.png\" alt=\"\" class=\"wp-image-242\" srcset=\"https:\/\/www.mitango.app\/app\/uploads\/2024\/11\/ajax-1024x681.png 1024w, https:\/\/www.mitango.app\/app\/uploads\/2024\/11\/ajax-300x200.png 300w, https:\/\/www.mitango.app\/app\/uploads\/2024\/11\/ajax-768x511.png 768w, https:\/\/www.mitango.app\/app\/uploads\/2024\/11\/ajax-18x12.png 18w, https:\/\/www.mitango.app\/app\/uploads\/2024\/11\/ajax.png 1127w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"the-example\">The example<\/h3>\n\n\n\n<p>To better picture the process, it is necessary to use some code that will be tested rather than just keep the code in that tutorial abstract and generic.<\/p>\n\n\n\n<p>That is why we will be testing the following code:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>add_action('wp_ajax_update_post', 'update_post_title');\n\nfunction update_post_title() {\n   if(! isset($_GET&#91;'_wpnonce']) || ! isset($_GET&#91;'post_id']) || ! wp_verify_nonce( sanitize_key( $_GET&#91;'_wpnonce'] ), 'update_post_title' . (int) $_GET&#91;'post_id'] ) ) {\n     return wp_die();\n   }\n\n   if( ! isset( $_POST&#91;'post_title'] ) ) {\n    return wp_die();\n   }\n\n   $post_title = sanitize_key( $_GET&#91;'post_title'] );\n\n   $post_id = $_POST&#91;'post_id'];\n\n   $post = get_post( $post_id );\n\n   if( ! $post ) {\n     return wp_send_json( &#91;] );\n   }\n\n   $post-&gt;title = $post_title;\n\n   wp_update_post($post);\n\n   return wp_send_json( &#91;\n     'title' =&gt; $post_title\n   ] );\n}<\/code><\/pre>\n\n\n\n<p>The objective from that code is to update the title from a post and return the updated title.<\/p>\n\n\n\n<p>This example is quite complete as it is covering all the different interactions we can have with the Ajax request.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"creating-the-testcase\">Creating the testcase<\/h2>\n\n\n\n<p>The best way to create an Ajax testcase is to extend from the class <code>AjaxTestCase<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>use WPMedia\\PHPUnit\\Integration\\AjaxTestCase;\n\nclass MyTest extends AjaxTestCase {\n\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"creating-the-test-method\">Creating the test method<\/h3>\n\n\n\n<p>For that it is necessary to create a public method with the world <code>test<\/code> inside it.<\/p>\n\n\n\n<p>In this example, that will be <code>testShouldDoAsExpected<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>use WPMedia\\PHPUnit\\Integration\\AjaxTestCase;\n\nclass MyTest extends AjaxTestCase {\n   public function testShouldDoAsExpected() {\n  \n   }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"setup-the-initial-word-press-state\">Setup the initial WordPress state<\/h3>\n\n\n\n<p>In our scenario we will be testing the ideal scenario where everything is working fine.<\/p>\n\n\n\n<p>Due to that we need to create the post that we will be modification.<\/p>\n\n\n\n<p>For that we will have to write the following code inside the test method:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>$post_id = $this-&gt;factory()-&gt;post-&gt;create(&#91;\n   'title' =&gt; 'old title'\n]);<\/code><\/pre>\n\n\n\n<p>You can notice that we are creating the post using a factory to create the post.<\/p>\n\n\n\n<p>It is an easy to be able different standard WordPress entities as such as users, posts or categories.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"initializing-the-request\">Initializing the request<\/h3>\n\n\n\n<p>The next step is to setup the request that will be sent to the the Ajax action.<\/p>\n\n\n\n<p>For that it is possible to directly affect values to the <code>$_GET<\/code> global variable that will be automatically reset. <\/p>\n\n\n\n<p>In that example there are three things to setup:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>The nonce: <\/strong>Check if the request is from an authorize user.<\/li>\n\n\n\n<li><strong>The post ID:<\/strong> The ID from the post that will be generated.<\/li>\n\n\n\n<li><strong>The new post title:<\/strong> The new title from the post.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>$_GET&#91;'_wpnonce'] = wp_create_nonce( 'update_post_title'.$post_id );\n$_GET&#91;'post_id'] = $post_id;\n$_GET&#91;'post_title'] = 'New title';<\/code><\/pre>\n\n\n\n<p>The next thing to setup is the action the request will be sent to with the following code:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>$this-&gt;action = 'update_post';<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"sending-the-ajax-request\">Sending the Ajax request<\/h3>\n\n\n\n<p>Once the Ajax request is ready it is then time to send it.<\/p>\n\n\n\n<p>For that it is possible to use the method <code>callAjaxAction<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>$response = $this-&gt;callAjaxAction();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"assert-on-the-response\">Assert on the response<\/h3>\n\n\n\n<p>When the logic to test is executed it is time to make sure the results from the request are the ones expected.<\/p>\n\n\n\n<p>For it is possible to make assertions on response from the request which is provided as return from the method callAjaxAction:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>$this-&gt;assertTrue( $response-&gt;success );\n$this-&gt;assertSame( 'New title', $response-&gt;data-&gt;title );<\/code><\/pre>\n\n\n\n<p>Inside this example it is possible to make sure the request is successful by checking the property <code>success<\/code>  and then check if the data is returned inside <code>data.title<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"assert-the-final-state\">Assert the final state<\/h3>\n\n\n\n<p>The last thing to do in the test is to make sure that the WordPress website is in the right final state.<\/p>\n\n\n\n<p>In that example, it is possible by checking the current title from the post:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>$post = get_post( $post_id );\n$this-&gt;assertSame( 'New title', $post-&gt;title );<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"overall-code\">Overall code<\/h3>\n\n\n\n<p>It can be sometimes hard to follow code that is exploded in many pieces, this is why a full version from the code is available here:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>use WPMedia\\PHPUnit\\Integration\\AjaxTestCase;\n\nclass MyTest extends AjaxTestCase {\n   public function testShouldDoAsExpected() {\n     $post_id = $this-&gt;factory()-&gt;post-&gt;create(&#91;\n      'title' =&gt; 'old title'\n     ]);\n\n     $_GET&#91;'_wpnonce'] = wp_create_nonce( 'update_post_title'.$post_id );\n     $_GET&#91;'post_id'] = $post_id;\n     $_GET&#91;'post_title'] = 'New title';\n\n     $this-&gt;action = 'update_post';\n\n     $response = $this-&gt;callAjaxAction();\n\n    $this-&gt;assertTrue( $response-&gt;success );\n    $this-&gt;assertSame( 'New title', $response-&gt;data-&gt;title );\n\n    $post = get_post( $post_id );\n    $this-&gt;assertSame( 'New title', $post-&gt;title );\n   }\n}<\/code><\/pre>\n\n\n\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>In some occasions it is essential to use Ajax request inside your plugin.<\/p>\n<p>In that article we will see how it is possible to test your Ajax requests using integration tests.<\/p>","protected":false},"author":1,"featured_media":162,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[26,18],"tags":[20,22,5,49],"class_list":["post-241","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-testing","category-wordpress","tag-plugin-development","tag-testing","tag-wordpress","tag-wordpress-development"],"jetpack_publicize_connections":[],"acf":[],"_links":{"self":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts\/241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/comments?post=241"}],"version-history":[{"count":10,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts\/241\/revisions"}],"predecessor-version":[{"id":449,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts\/241\/revisions\/449"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/media\/162"}],"wp:attachment":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/media?parent=241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/categories?post=241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/tags?post=241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}