- Added GitHub spec-kit for development workflow - Standardized file signatures to Descomplicar® format - Updated development configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
431 lines
14 KiB
PHP
431 lines
14 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
/**
|
|
* Contract test for wp_ajax_care_booking_toggle_restriction endpoint
|
|
*
|
|
* @package CareBookingBlock
|
|
*/
|
|
|
|
/**
|
|
* Test AJAX endpoint: wp_ajax_care_booking_toggle_restriction
|
|
*/
|
|
class Test_Ajax_Toggle_Restriction extends Care_Booking_Test_Case
|
|
{
|
|
|
|
/**
|
|
* Test AJAX handler is registered
|
|
*/
|
|
public function test_ajax_handler_registered()
|
|
{
|
|
$this->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');
|
|
}
|
|
} |