- 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>
521 lines
17 KiB
PHP
521 lines
17 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
/**
|
|
* Contract test for wp_ajax_care_booking_get_entities endpoint
|
|
*
|
|
* @package CareBookingBlock
|
|
*/
|
|
|
|
/**
|
|
* Test AJAX endpoint: wp_ajax_care_booking_get_entities
|
|
*/
|
|
class Test_Ajax_Get_Entities extends Care_Booking_Test_Case
|
|
{
|
|
|
|
/**
|
|
* Test AJAX handler is registered
|
|
*/
|
|
public function test_ajax_handler_registered()
|
|
{
|
|
$this->assertTrue(has_action('wp_ajax_care_booking_get_entities'), 'AJAX handler should be registered');
|
|
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_get_entities'), 'Non-privileged AJAX should not be registered');
|
|
}
|
|
|
|
/**
|
|
* Test successful doctors retrieval
|
|
*/
|
|
public function test_successful_doctors_retrieval()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Create some test restrictions to show restriction status
|
|
$this->create_test_doctor_restriction(999, true);
|
|
$this->create_test_doctor_restriction(998, false);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} 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('entities', $data['data']);
|
|
$this->assertArrayHasKey('total', $data['data']);
|
|
$this->assertIsArray($data['data']['entities']);
|
|
$this->assertIsInt($data['data']['total']);
|
|
|
|
// Test entity structure if entities exist
|
|
if (!empty($data['data']['entities'])) {
|
|
$entity = $data['data']['entities'][0];
|
|
$this->assertArrayHasKey('id', $entity);
|
|
$this->assertArrayHasKey('name', $entity);
|
|
$this->assertArrayHasKey('email', $entity);
|
|
$this->assertArrayHasKey('is_blocked', $entity);
|
|
$this->assertIsBool($entity['is_blocked']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test successful services retrieval
|
|
*/
|
|
public function test_successful_services_retrieval()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Create service restriction for testing status
|
|
$this->create_test_service_restriction(888, 999, true);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'services'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
$this->assertArrayHasKey('entities', $data['data']);
|
|
$this->assertArrayHasKey('total', $data['data']);
|
|
|
|
// Test service entity structure if services exist
|
|
if (!empty($data['data']['entities'])) {
|
|
$service = $data['data']['entities'][0];
|
|
$this->assertArrayHasKey('id', $service);
|
|
$this->assertArrayHasKey('name', $service);
|
|
$this->assertArrayHasKey('doctor_id', $service);
|
|
$this->assertArrayHasKey('is_blocked', $service);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test services retrieval filtered by doctor
|
|
*/
|
|
public function test_services_filtered_by_doctor()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Create services for different doctors
|
|
$this->create_test_service_restriction(888, 999, true);
|
|
$this->create_test_service_restriction(887, 998, false);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'services',
|
|
'doctor_id' => 999
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
// Should only return services for doctor 999
|
|
if (!empty($data['data']['entities'])) {
|
|
foreach ($data['data']['entities'] as $service) {
|
|
$this->assertEquals(999, $service['doctor_id'], 'All services should belong to doctor 999');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test invalid nonce returns error
|
|
*/
|
|
public function test_invalid_nonce_error()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => 'invalid_nonce',
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} 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_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} 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 invalid entity type returns error
|
|
*/
|
|
public function test_invalid_entity_type_error()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'invalid_type'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, false);
|
|
$this->assertEquals('Invalid entity type', $data['data']['message']);
|
|
}
|
|
|
|
/**
|
|
* Test missing entity_type parameter
|
|
*/
|
|
public function test_missing_entity_type_parameter()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities')
|
|
// Missing entity_type parameter
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, false);
|
|
$this->assertEquals('Missing entity_type parameter', $data['data']['message']);
|
|
}
|
|
|
|
/**
|
|
* Test KiviCare plugin not available
|
|
*/
|
|
public function test_kivicare_not_available()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Mock KiviCare as not available
|
|
add_filter('pre_option_active_plugins', function($plugins) {
|
|
return []; // No active plugins
|
|
});
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
remove_all_filters('pre_option_active_plugins');
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, false);
|
|
$this->assertEquals('KiviCare plugin not available', $data['data']['message']);
|
|
}
|
|
|
|
/**
|
|
* Test empty results return correct structure
|
|
*/
|
|
public function test_empty_results()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Mock empty KiviCare tables
|
|
global $wpdb;
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
$this->assertIsArray($data['data']['entities']);
|
|
$this->assertEquals(0, $data['data']['total']);
|
|
}
|
|
|
|
/**
|
|
* Test response time performance requirement
|
|
*/
|
|
public function test_response_time_performance()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
$start_time = microtime(true);
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$end_time = microtime(true);
|
|
$response_time = ($end_time - $start_time) * 1000;
|
|
|
|
$this->assertLessThan(400, $response_time, 'Response time should be under 400ms according to contract');
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
}
|
|
|
|
/**
|
|
* Test restriction status accuracy
|
|
*/
|
|
public function test_restriction_status_accuracy()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Create known restrictions
|
|
$this->create_test_doctor_restriction(999, true); // Blocked
|
|
$this->create_test_doctor_restriction(998, false); // Not blocked
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
// Find our test doctors and verify restriction status
|
|
foreach ($data['data']['entities'] as $doctor) {
|
|
if ($doctor['id'] == 999) {
|
|
$this->assertTrue($doctor['is_blocked'], 'Doctor 999 should be marked as blocked');
|
|
} elseif ($doctor['id'] == 998) {
|
|
$this->assertFalse($doctor['is_blocked'], 'Doctor 998 should not be marked as blocked');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test service restriction status with doctor context
|
|
*/
|
|
public function test_service_restriction_status_with_doctor()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
// Create service restrictions for specific doctors
|
|
$this->create_test_service_restriction(888, 999, true); // Service 888 blocked for doctor 999
|
|
$this->create_test_service_restriction(888, 998, false); // Service 888 not blocked for doctor 998
|
|
|
|
// Get services for doctor 999
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'services',
|
|
'doctor_id' => 999
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
// Check service 888 status for doctor 999
|
|
foreach ($data['data']['entities'] as $service) {
|
|
if ($service['id'] == 888) {
|
|
$this->assertTrue($service['is_blocked'], 'Service 888 should be blocked for doctor 999');
|
|
}
|
|
}
|
|
|
|
// Get services for doctor 998
|
|
$_POST['doctor_id'] = 998;
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
// Check service 888 status for doctor 998
|
|
foreach ($data['data']['entities'] as $service) {
|
|
if ($service['id'] == 888) {
|
|
$this->assertFalse($service['is_blocked'], 'Service 888 should not be blocked for doctor 998');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} 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->assertContains('Database error', $data['data']['message']);
|
|
}
|
|
|
|
/**
|
|
* Test large dataset handling
|
|
*/
|
|
public function test_large_dataset_handling()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
// This test verifies the system can handle large result sets
|
|
// without timing out or running into memory issues
|
|
$start_memory = memory_get_usage();
|
|
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$response = ob_get_clean();
|
|
|
|
$end_memory = memory_get_usage();
|
|
$memory_used = $end_memory - $start_memory;
|
|
|
|
// Memory usage should be reasonable (less than 10MB for the operation)
|
|
$this->assertLessThan(10 * 1024 * 1024, $memory_used, 'Memory usage should be reasonable');
|
|
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
}
|
|
|
|
/**
|
|
* Test concurrent request handling
|
|
*/
|
|
public function test_concurrent_request_handling()
|
|
{
|
|
$this->set_current_user($this->admin_user_id);
|
|
|
|
$_POST = [
|
|
'action' => 'care_booking_get_entities',
|
|
'nonce' => $this->mock_wp_nonce('care_booking_get_entities'),
|
|
'entity_type' => 'doctors'
|
|
];
|
|
|
|
// Simulate multiple concurrent requests
|
|
$responses = [];
|
|
|
|
for ($i = 0; $i < 3; $i++) {
|
|
ob_start();
|
|
try {
|
|
do_action('wp_ajax_care_booking_get_entities');
|
|
} catch (WPAjaxDieStopException $e) {}
|
|
$responses[] = ob_get_clean();
|
|
}
|
|
|
|
// All responses should be valid and consistent
|
|
foreach ($responses as $response) {
|
|
$data = json_decode($response, true);
|
|
$this->assert_ajax_response($data, true);
|
|
|
|
// Structure should be consistent across all responses
|
|
$this->assertArrayHasKey('entities', $data['data']);
|
|
$this->assertArrayHasKey('total', $data['data']);
|
|
}
|
|
}
|
|
} |