/** * Descomplicar® Crescimento Digital * https://descomplicar.pt */ assertTrue(has_action('wp_ajax_care_booking_toggle_restriction'), 'AJAX handler should be registered'); $this->assertFalse(has_action('wp_ajax_nopriv_care_booking_toggle_restriction'), 'Non-privileged AJAX should not be registered'); } /** * Test successful doctor restriction toggle */ public function test_successful_doctor_restriction_toggle() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, true); // Test response structure according to contract $this->assertArrayHasKey('message', $data['data']); $this->assertArrayHasKey('restriction', $data['data']); $this->assertEquals('Restriction updated successfully', $data['data']['message']); // Test restriction object structure $restriction = $data['data']['restriction']; $this->assertArrayHasKey('id', $restriction); $this->assertArrayHasKey('restriction_type', $restriction); $this->assertArrayHasKey('target_id', $restriction); $this->assertArrayHasKey('doctor_id', $restriction); $this->assertArrayHasKey('is_blocked', $restriction); $this->assertArrayHasKey('updated_at', $restriction); // Test values match request $this->assertEquals('doctor', $restriction['restriction_type']); $this->assertEquals(999, $restriction['target_id']); $this->assertNull($restriction['doctor_id']); $this->assertTrue($restriction['is_blocked']); } /** * Test successful service restriction toggle */ public function test_successful_service_restriction_toggle() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'service', 'target_id' => 888, 'doctor_id' => 999, 'is_blocked' => false ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, true); $restriction = $data['data']['restriction']; $this->assertEquals('service', $restriction['restriction_type']); $this->assertEquals(888, $restriction['target_id']); $this->assertEquals(999, $restriction['doctor_id']); $this->assertFalse($restriction['is_blocked']); } /** * Test toggle existing restriction (update operation) */ public function test_toggle_existing_restriction() { $this->set_current_user($this->admin_user_id); // Create initial restriction $restriction_id = $this->create_test_doctor_restriction(999, true); // Toggle to unblocked $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => false ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, true); // Should return same restriction ID but updated $this->assertEquals($restriction_id, $data['data']['restriction']['id']); $this->assertFalse($data['data']['restriction']['is_blocked']); } /** * Test invalid nonce returns error */ public function test_invalid_nonce_error() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => 'invalid_nonce', 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertEquals('Invalid nonce', $data['data']['message']); } /** * Test insufficient permissions returns error */ public function test_insufficient_permissions_error() { $subscriber_id = $this->factory->user->create(['role' => 'subscriber']); $this->set_current_user($subscriber_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertEquals('Insufficient permissions', $data['data']['message']); } /** * Test missing required parameters */ public function test_missing_required_parameters() { $this->set_current_user($this->admin_user_id); // Missing target_id $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertContains('Missing required parameter', $data['data']['message']); } /** * Test invalid restriction type */ public function test_invalid_restriction_type() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'invalid_type', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertEquals('Invalid restriction type', $data['data']['message']); } /** * Test service restriction without doctor_id */ public function test_service_restriction_without_doctor_id() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'service', 'target_id' => 888, 'is_blocked' => true // Missing doctor_id for service restriction ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertEquals('doctor_id required for service restrictions', $data['data']['message']); } /** * Test target not found in KiviCare */ public function test_target_not_found() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 99999, // Non-existent doctor 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertEquals('Target not found', $data['data']['message']); } /** * Test database error handling */ public function test_database_error_handling() { $this->set_current_user($this->admin_user_id); // Mock database error global $wpdb; $original_prefix = $wpdb->prefix; $wpdb->prefix = 'invalid_prefix_'; $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); // Restore prefix $wpdb->prefix = $original_prefix; $data = json_decode($response, true); $this->assert_ajax_response($data, false); $this->assertEquals('Database error', $data['data']['message']); } /** * Test response time performance requirement */ public function test_response_time_performance() { $this->set_current_user($this->admin_user_id); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; $start_time = microtime(true); ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $end_time = microtime(true); $response_time = ($end_time - $start_time) * 1000; $this->assertLessThan(300, $response_time, 'Response time should be under 300ms according to contract'); $data = json_decode($response, true); $this->assert_ajax_response($data, true); } /** * Test cache invalidation after toggle */ public function test_cache_invalidation_after_toggle() { $this->set_current_user($this->admin_user_id); // Set initial cache set_transient('care_booking_doctors_blocked', [998], 3600); $this->assertNotFalse(get_transient('care_booking_doctors_blocked')); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, true); // Cache should be invalidated $this->assertFalse(get_transient('care_booking_doctors_blocked'), 'Cache should be invalidated after toggle'); } /** * Test WordPress action triggered after successful toggle */ public function test_action_triggered_after_toggle() { $this->set_current_user($this->admin_user_id); $action_fired = false; $action_args = []; // Hook to test action add_action('care_booking_restriction_updated', function($type, $target_id, $doctor_id = null) use (&$action_fired, &$action_args) { $action_fired = true; $action_args = [$type, $target_id, $doctor_id]; }, 10, 3); $_POST = [ 'action' => 'care_booking_toggle_restriction', 'nonce' => $this->mock_wp_nonce('care_booking_toggle_restriction'), 'restriction_type' => 'doctor', 'target_id' => 999, 'is_blocked' => true ]; ob_start(); try { do_action('wp_ajax_care_booking_toggle_restriction'); } catch (WPAjaxDieStopException $e) {} $response = ob_get_clean(); $data = json_decode($response, true); $this->assert_ajax_response($data, true); // Action should have fired $this->assertTrue($action_fired, 'care_booking_restriction_updated action should fire'); $this->assertEquals(['doctor', 999, null], $action_args, 'Action should receive correct arguments'); } }