chore: add spec-kit and standardize signatures
- 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>
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
/**
|
||||
* Descomplicar® Crescimento Digital
|
||||
* https://descomplicar.pt
|
||||
*/
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Contract test for wp_ajax_care_booking_bulk_update endpoint
|
||||
*
|
||||
* @package CareBookingBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test AJAX endpoint: wp_ajax_care_booking_bulk_update
|
||||
*/
|
||||
class Test_Ajax_Bulk_Update extends Care_Booking_Test_Case
|
||||
{
|
||||
|
||||
/**
|
||||
* Test AJAX handler is registered
|
||||
*/
|
||||
public function test_ajax_handler_registered()
|
||||
{
|
||||
$this->assertTrue(has_action('wp_ajax_care_booking_bulk_update'), 'AJAX handler should be registered');
|
||||
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_bulk_update'), 'Non-privileged AJAX should not be registered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successful bulk update with mixed restrictions
|
||||
*/
|
||||
public function test_successful_bulk_update()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$restrictions = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 998,
|
||||
'is_blocked' => false
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 888,
|
||||
'doctor_id' => 999,
|
||||
'is_blocked' => true
|
||||
]
|
||||
];
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} 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('updated', $data['data']);
|
||||
$this->assertArrayHasKey('errors', $data['data']);
|
||||
|
||||
$this->assertEquals('Bulk update completed', $data['data']['message']);
|
||||
$this->assertEquals(3, $data['data']['updated']);
|
||||
$this->assertEmpty($data['data']['errors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test bulk update with some failures
|
||||
*/
|
||||
public function test_bulk_update_with_partial_failures()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$restrictions = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'invalid_type', // This should fail
|
||||
'target_id' => 998,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 888,
|
||||
'doctor_id' => 999,
|
||||
'is_blocked' => true
|
||||
]
|
||||
];
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false); // Partial failure should return false
|
||||
|
||||
$this->assertEquals('Partial failure in bulk update', $data['data']['message']);
|
||||
$this->assertEquals(2, $data['data']['updated']); // Only 2 successful
|
||||
$this->assertCount(1, $data['data']['errors']); // 1 error
|
||||
|
||||
// Check error structure
|
||||
$error = $data['data']['errors'][0];
|
||||
$this->assertArrayHasKey('restriction', $error);
|
||||
$this->assertArrayHasKey('error', $error);
|
||||
$this->assertEquals('invalid_type', $error['restriction']['restriction_type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test bulk update with KiviCare target validation
|
||||
*/
|
||||
public function test_bulk_update_with_target_validation()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$restrictions = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 99999, // Non-existent doctor
|
||||
'is_blocked' => true
|
||||
]
|
||||
];
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
|
||||
$this->assertEquals(0, $data['data']['updated']);
|
||||
$this->assertCount(1, $data['data']['errors']);
|
||||
$this->assertContains('Target not found in KiviCare', $data['data']['errors'][0]['error']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invalid nonce returns error
|
||||
*/
|
||||
public function test_invalid_nonce_error()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => 'invalid_nonce',
|
||||
'restrictions' => []
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} 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_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => []
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} 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 empty restrictions array
|
||||
*/
|
||||
public function test_empty_restrictions_array()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => []
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
|
||||
$this->assertEquals('Bulk update completed', $data['data']['message']);
|
||||
$this->assertEquals(0, $data['data']['updated']);
|
||||
$this->assertEmpty($data['data']['errors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test missing restrictions parameter
|
||||
*/
|
||||
public function test_missing_restrictions_parameter()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update')
|
||||
// Missing 'restrictions' parameter
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
$this->assertEquals('Missing restrictions parameter', $data['data']['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invalid restrictions format
|
||||
*/
|
||||
public function test_invalid_restrictions_format()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => 'invalid_format' // Should be array
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
$this->assertEquals('Invalid restrictions format', $data['data']['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test response time performance requirement for bulk operation
|
||||
*/
|
||||
public function test_response_time_performance()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Create bulk data (50 items as per contract)
|
||||
$restrictions = [];
|
||||
for ($i = 1; $i <= 50; $i++) {
|
||||
$restrictions[] = [
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 900 + $i,
|
||||
'is_blocked' => $i % 2 === 0
|
||||
];
|
||||
}
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
$start_time = microtime(true);
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$end_time = microtime(true);
|
||||
$response_time = ($end_time - $start_time) * 1000;
|
||||
|
||||
$this->assertLessThan(500, $response_time, 'Bulk update should complete in under 500ms for 50 items');
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
$this->assertEquals(50, $data['data']['updated']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test transaction rollback on critical errors
|
||||
*/
|
||||
public function test_transaction_rollback_on_critical_error()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$restrictions = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 998,
|
||||
'is_blocked' => true
|
||||
]
|
||||
];
|
||||
|
||||
// Mock database error during processing
|
||||
global $wpdb;
|
||||
|
||||
// Hook into database operations to simulate error
|
||||
add_filter('query', function($query) {
|
||||
if (strpos($query, 'care_booking_restrictions') !== false && strpos($query, '998') !== false) {
|
||||
return 'SELECT * FROM non_existent_table'; // Force error
|
||||
}
|
||||
return $query;
|
||||
});
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
// Remove filter
|
||||
remove_all_filters('query');
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
|
||||
// Verify partial processing occurred with error handling
|
||||
$this->assertIsInt($data['data']['updated']);
|
||||
$this->assertIsArray($data['data']['errors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache invalidation after bulk update
|
||||
*/
|
||||
public function test_cache_invalidation_after_bulk_update()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Set initial cache
|
||||
set_transient('care_booking_doctors_blocked', [997], 3600);
|
||||
set_transient('care_booking_services_blocked_999', [886], 3600);
|
||||
|
||||
$this->assertNotFalse(get_transient('care_booking_doctors_blocked'));
|
||||
$this->assertNotFalse(get_transient('care_booking_services_blocked_999'));
|
||||
|
||||
$restrictions = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
]
|
||||
];
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} 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'));
|
||||
$this->assertFalse(get_transient('care_booking_services_blocked_999'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test WordPress action triggered after bulk update
|
||||
*/
|
||||
public function test_action_triggered_after_bulk_update()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$actions_fired = [];
|
||||
|
||||
add_action('care_booking_restriction_updated', function($type, $target_id, $doctor_id = null) use (&$actions_fired) {
|
||||
$actions_fired[] = [$type, $target_id, $doctor_id];
|
||||
}, 10, 3);
|
||||
|
||||
$restrictions = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 888,
|
||||
'doctor_id' => 999,
|
||||
'is_blocked' => false
|
||||
]
|
||||
];
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
|
||||
// Actions should have fired for each restriction
|
||||
$this->assertCount(2, $actions_fired);
|
||||
$this->assertContains(['doctor', 999, null], $actions_fired);
|
||||
$this->assertContains(['service', 888, 999], $actions_fired);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test maximum bulk size limit
|
||||
*/
|
||||
public function test_maximum_bulk_size_limit()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Create oversized bulk request (more than allowed)
|
||||
$restrictions = [];
|
||||
for ($i = 1; $i <= 101; $i++) { // Over 100 items limit
|
||||
$restrictions[] = [
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 800 + $i,
|
||||
'is_blocked' => true
|
||||
];
|
||||
}
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_bulk_update',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_bulk_update'),
|
||||
'restrictions' => $restrictions
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_bulk_update');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
$this->assertEquals('Bulk size limit exceeded', $data['data']['message']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
/**
|
||||
* 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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
/**
|
||||
* Descomplicar® Crescimento Digital
|
||||
* https://descomplicar.pt
|
||||
*/
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Contract test for wp_ajax_care_booking_get_restrictions endpoint
|
||||
*
|
||||
* @package CareBookingBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test AJAX endpoint: wp_ajax_care_booking_get_restrictions
|
||||
*/
|
||||
class Test_Ajax_Get_Restrictions 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_restrictions'), 'AJAX handler should be registered');
|
||||
$this->assertFalse(has_action('wp_ajax_nopriv_care_booking_get_restrictions'), 'Non-privileged AJAX should not be registered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successful request returns correct structure
|
||||
*/
|
||||
public function test_successful_request_structure()
|
||||
{
|
||||
// Set up admin user
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Create test restrictions
|
||||
$this->create_test_doctor_restriction(999, true);
|
||||
$this->create_test_service_restriction(888, 999, false);
|
||||
|
||||
// Mock AJAX request
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
// Capture AJAX response
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {
|
||||
// Expected for wp_die() in AJAX handlers
|
||||
}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
|
||||
// Test response structure according to contract
|
||||
$this->assert_ajax_response($data, true);
|
||||
|
||||
$this->assertArrayHasKey('restrictions', $data['data']);
|
||||
$this->assertArrayHasKey('total', $data['data']);
|
||||
$this->assertIsArray($data['data']['restrictions']);
|
||||
$this->assertIsInt($data['data']['total']);
|
||||
|
||||
// Test restriction object structure
|
||||
$this->assertGreaterThan(0, count($data['data']['restrictions']));
|
||||
$restriction = $data['data']['restrictions'][0];
|
||||
|
||||
$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('created_at', $restriction);
|
||||
$this->assertArrayHasKey('updated_at', $restriction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test filter by restriction type
|
||||
*/
|
||||
public function test_filter_by_restriction_type()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Create different types
|
||||
$this->create_test_doctor_restriction(999, true);
|
||||
$this->create_test_service_restriction(888, 999, true);
|
||||
|
||||
// Test filter by doctor
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'doctor'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
|
||||
// Should only return doctor restrictions
|
||||
foreach ($data['data']['restrictions'] as $restriction) {
|
||||
$this->assertEquals('doctor', $restriction['restriction_type']);
|
||||
}
|
||||
|
||||
// Test filter by service
|
||||
$_POST['restriction_type'] = 'service';
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
|
||||
// Should only return service restrictions
|
||||
foreach ($data['data']['restrictions'] as $restriction) {
|
||||
$this->assertEquals('service', $restriction['restriction_type']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test filter by doctor for service restrictions
|
||||
*/
|
||||
public function test_filter_services_by_doctor()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Create service restrictions for different doctors
|
||||
$this->create_test_service_restriction(888, 999, true);
|
||||
$this->create_test_service_restriction(887, 998, true);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'service',
|
||||
'doctor_id' => 999
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} 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
|
||||
foreach ($data['data']['restrictions'] as $restriction) {
|
||||
$this->assertEquals('service', $restriction['restriction_type']);
|
||||
$this->assertEquals(999, $restriction['doctor_id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invalid nonce returns error
|
||||
*/
|
||||
public function test_invalid_nonce_error()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => 'invalid_nonce',
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} 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()
|
||||
{
|
||||
// Create subscriber user (no manage_options capability)
|
||||
$subscriber_id = $this->factory->user->create(['role' => 'subscriber']);
|
||||
$this->set_current_user($subscriber_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} 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 parameters return error
|
||||
*/
|
||||
public function test_invalid_parameters_error()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'invalid_type'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
$this->assertEquals('Invalid parameters', $data['data']['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test empty results return correct structure
|
||||
*/
|
||||
public function test_empty_results()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
|
||||
$this->assertIsArray($data['data']['restrictions']);
|
||||
$this->assertEmpty($data['data']['restrictions']);
|
||||
$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);
|
||||
|
||||
// Create test data
|
||||
for ($i = 1; $i <= 50; $i++) {
|
||||
$this->create_test_doctor_restriction(900 + $i, $i % 2 === 0);
|
||||
}
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
$start_time = microtime(true);
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
$end_time = microtime(true);
|
||||
$response_time = ($end_time - $start_time) * 1000; // Convert to milliseconds
|
||||
|
||||
$this->assertLessThan(200, $response_time, 'Response time should be under 200ms according to contract');
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, true);
|
||||
$this->assertEquals(50, $data['data']['total']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JSON response format compliance
|
||||
*/
|
||||
public function test_json_response_format()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
// Test valid JSON
|
||||
$data = json_decode($response, true);
|
||||
$this->assertNotNull($data, 'Response should be valid JSON');
|
||||
$this->assertEquals(JSON_ERROR_NONE, json_last_error(), 'JSON should be valid');
|
||||
|
||||
// Test WordPress AJAX standard format
|
||||
$this->assertArrayHasKey('success', $data);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
$this->assertIsBool($data['success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database error handling
|
||||
*/
|
||||
public function test_database_error_handling()
|
||||
{
|
||||
$this->set_current_user($this->admin_user_id);
|
||||
|
||||
// Mock database error by temporarily corrupting table name
|
||||
global $wpdb;
|
||||
$original_prefix = $wpdb->prefix;
|
||||
$wpdb->prefix = 'invalid_prefix_';
|
||||
|
||||
$_POST = [
|
||||
'action' => 'care_booking_get_restrictions',
|
||||
'nonce' => $this->mock_wp_nonce('care_booking_get_restrictions'),
|
||||
'restriction_type' => 'all'
|
||||
];
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
do_action('wp_ajax_care_booking_get_restrictions');
|
||||
} catch (WPAjaxDieStopException $e) {}
|
||||
$response = ob_get_clean();
|
||||
|
||||
// Restore database prefix
|
||||
$wpdb->prefix = $original_prefix;
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$this->assert_ajax_response($data, false);
|
||||
$this->assertContains('Database error', $data['data']['message']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
/**
|
||||
* 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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* Descomplicar® Crescimento Digital
|
||||
* https://descomplicar.pt
|
||||
*/
|
||||
|
||||
<?php
|
||||
/**
|
||||
* WordPress cache integration tests for Care Booking Block plugin
|
||||
*
|
||||
* @package CareBookingBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test WordPress cache integration functionality
|
||||
*/
|
||||
class Test_Cache_Integration extends Care_Booking_Test_Case
|
||||
{
|
||||
|
||||
/**
|
||||
* Test cache manager class exists and can be instantiated
|
||||
*/
|
||||
public function test_cache_manager_class_exists()
|
||||
{
|
||||
$this->assertTrue(class_exists('Care_Booking_Cache_Manager'), 'Care_Booking_Cache_Manager class should exist');
|
||||
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
$this->assertInstanceOf('Care_Booking_Cache_Manager', $cache_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache blocked doctors list
|
||||
*/
|
||||
public function test_cache_blocked_doctors()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
$blocked_doctors = [999, 998, 997];
|
||||
|
||||
// Set cache
|
||||
$result = $cache_manager->set_blocked_doctors($blocked_doctors);
|
||||
$this->assertTrue($result, 'Should successfully cache blocked doctors');
|
||||
|
||||
// Get from cache
|
||||
$cached_doctors = $cache_manager->get_blocked_doctors();
|
||||
$this->assertIsArray($cached_doctors, 'Should return array from cache');
|
||||
$this->assertEquals($blocked_doctors, $cached_doctors, 'Cached data should match original data');
|
||||
|
||||
// Verify WordPress transient was set
|
||||
$transient_data = get_transient('care_booking_doctors_blocked');
|
||||
$this->assertEquals($blocked_doctors, $transient_data, 'WordPress transient should contain correct data');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache blocked services for doctor
|
||||
*/
|
||||
public function test_cache_blocked_services_by_doctor()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
$doctor_id = 999;
|
||||
$blocked_services = [888, 887, 886];
|
||||
|
||||
// Set cache
|
||||
$result = $cache_manager->set_blocked_services($doctor_id, $blocked_services);
|
||||
$this->assertTrue($result, 'Should successfully cache blocked services');
|
||||
|
||||
// Get from cache
|
||||
$cached_services = $cache_manager->get_blocked_services($doctor_id);
|
||||
$this->assertIsArray($cached_services);
|
||||
$this->assertEquals($blocked_services, $cached_services);
|
||||
|
||||
// Verify WordPress transient was set with correct key
|
||||
$transient_key = "care_booking_services_blocked_$doctor_id";
|
||||
$transient_data = get_transient($transient_key);
|
||||
$this->assertEquals($blocked_services, $transient_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache expiration
|
||||
*/
|
||||
public function test_cache_expiration()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Set short expiration for testing
|
||||
$blocked_doctors = [999];
|
||||
$result = $cache_manager->set_blocked_doctors($blocked_doctors, 1); // 1 second expiration
|
||||
$this->assertTrue($result);
|
||||
|
||||
// Verify cache exists
|
||||
$cached_data = $cache_manager->get_blocked_doctors();
|
||||
$this->assertEquals($blocked_doctors, $cached_data);
|
||||
|
||||
// Wait for expiration
|
||||
sleep(2);
|
||||
|
||||
// Verify cache expired
|
||||
$expired_data = $cache_manager->get_blocked_doctors();
|
||||
$this->assertFalse($expired_data, 'Cache should expire after timeout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache invalidation
|
||||
*/
|
||||
public function test_cache_invalidation()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Set initial cache data
|
||||
$cache_manager->set_blocked_doctors([999, 998]);
|
||||
$cache_manager->set_blocked_services(999, [888, 887]);
|
||||
$cache_manager->set_blocked_services(998, [886]);
|
||||
|
||||
// Verify cache exists
|
||||
$this->assertNotFalse($cache_manager->get_blocked_doctors());
|
||||
$this->assertNotFalse($cache_manager->get_blocked_services(999));
|
||||
$this->assertNotFalse($cache_manager->get_blocked_services(998));
|
||||
|
||||
// Invalidate all cache
|
||||
$result = $cache_manager->invalidate_all();
|
||||
$this->assertTrue($result, 'Should successfully invalidate all cache');
|
||||
|
||||
// Verify cache was cleared
|
||||
$this->assertFalse($cache_manager->get_blocked_doctors(), 'Blocked doctors cache should be cleared');
|
||||
$this->assertFalse($cache_manager->get_blocked_services(999), 'Blocked services cache should be cleared');
|
||||
$this->assertFalse($cache_manager->get_blocked_services(998), 'Blocked services cache should be cleared');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache hash for change detection
|
||||
*/
|
||||
public function test_cache_hash_management()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Set initial hash
|
||||
$initial_hash = 'test_hash_123';
|
||||
$result = $cache_manager->set_restrictions_hash($initial_hash);
|
||||
$this->assertTrue($result);
|
||||
|
||||
// Get hash
|
||||
$cached_hash = $cache_manager->get_restrictions_hash();
|
||||
$this->assertEquals($initial_hash, $cached_hash);
|
||||
|
||||
// Update hash
|
||||
$new_hash = 'test_hash_456';
|
||||
$cache_manager->set_restrictions_hash($new_hash);
|
||||
|
||||
$updated_hash = $cache_manager->get_restrictions_hash();
|
||||
$this->assertEquals($new_hash, $updated_hash);
|
||||
$this->assertNotEquals($initial_hash, $updated_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache miss behavior
|
||||
*/
|
||||
public function test_cache_miss_behavior()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Test getting non-existent cache
|
||||
$non_existent_doctors = $cache_manager->get_blocked_doctors();
|
||||
$this->assertFalse($non_existent_doctors, 'Should return false for cache miss');
|
||||
|
||||
$non_existent_services = $cache_manager->get_blocked_services(123);
|
||||
$this->assertFalse($non_existent_services, 'Should return false for cache miss');
|
||||
|
||||
$non_existent_hash = $cache_manager->get_restrictions_hash();
|
||||
$this->assertFalse($non_existent_hash, 'Should return false for cache miss');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache key generation
|
||||
*/
|
||||
public function test_cache_key_generation()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Test different doctor IDs generate different cache keys
|
||||
$doctor1_services = [888];
|
||||
$doctor2_services = [887];
|
||||
|
||||
$cache_manager->set_blocked_services(999, $doctor1_services);
|
||||
$cache_manager->set_blocked_services(998, $doctor2_services);
|
||||
|
||||
// Verify separate caches
|
||||
$cached_services_1 = $cache_manager->get_blocked_services(999);
|
||||
$cached_services_2 = $cache_manager->get_blocked_services(998);
|
||||
|
||||
$this->assertEquals($doctor1_services, $cached_services_1);
|
||||
$this->assertEquals($doctor2_services, $cached_services_2);
|
||||
$this->assertNotEquals($cached_services_1, $cached_services_2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache size limits and memory usage
|
||||
*/
|
||||
public function test_cache_size_and_memory()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Test caching large dataset
|
||||
$large_doctor_list = range(1, 1000); // 1000 doctor IDs
|
||||
|
||||
$result = $cache_manager->set_blocked_doctors($large_doctor_list);
|
||||
$this->assertTrue($result, 'Should handle large datasets');
|
||||
|
||||
$cached_large_list = $cache_manager->get_blocked_doctors();
|
||||
$this->assertEquals($large_doctor_list, $cached_large_list, 'Large dataset should be cached correctly');
|
||||
$this->assertCount(1000, $cached_large_list, 'All items should be cached');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache with WordPress object cache compatibility
|
||||
*/
|
||||
public function test_wordpress_object_cache_compatibility()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Test with WordPress wp_cache functions if available
|
||||
if (function_exists('wp_cache_set') && function_exists('wp_cache_get')) {
|
||||
$test_data = [999, 998];
|
||||
|
||||
// Use WordPress object cache directly
|
||||
wp_cache_set('care_booking_test', $test_data, 'care_booking', 3600);
|
||||
$wp_cached_data = wp_cache_get('care_booking_test', 'care_booking');
|
||||
|
||||
$this->assertEquals($test_data, $wp_cached_data, 'WordPress object cache should work with plugin data');
|
||||
} else {
|
||||
$this->markTestSkipped('WordPress object cache not available in test environment');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache performance benchmarks
|
||||
*/
|
||||
public function test_cache_performance()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
$test_data = range(1, 100);
|
||||
|
||||
// Measure cache write performance
|
||||
$start_time = microtime(true);
|
||||
$cache_manager->set_blocked_doctors($test_data);
|
||||
$write_time = microtime(true) - $start_time;
|
||||
|
||||
$this->assertLessThan(0.1, $write_time, 'Cache write should complete in under 100ms');
|
||||
|
||||
// Measure cache read performance
|
||||
$start_time = microtime(true);
|
||||
$cached_data = $cache_manager->get_blocked_doctors();
|
||||
$read_time = microtime(true) - $start_time;
|
||||
|
||||
$this->assertLessThan(0.05, $read_time, 'Cache read should complete in under 50ms');
|
||||
$this->assertEquals($test_data, $cached_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache invalidation on restriction changes
|
||||
*/
|
||||
public function test_cache_invalidation_on_changes()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Set initial cache
|
||||
$cache_manager->set_blocked_doctors([999]);
|
||||
$cache_manager->set_blocked_services(999, [888]);
|
||||
|
||||
// Verify cache exists
|
||||
$this->assertNotFalse($cache_manager->get_blocked_doctors());
|
||||
$this->assertNotFalse($cache_manager->get_blocked_services(999));
|
||||
|
||||
// Simulate restriction change event
|
||||
do_action('care_booking_restriction_updated', 'doctor', 999);
|
||||
|
||||
// Cache should be automatically invalidated
|
||||
$this->assertFalse($cache_manager->get_blocked_doctors(), 'Cache should be invalidated on restriction change');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache with concurrent access
|
||||
*/
|
||||
public function test_concurrent_cache_access()
|
||||
{
|
||||
$cache_manager = new Care_Booking_Cache_Manager();
|
||||
|
||||
// Simulate concurrent writes (in real scenario this would be multiple requests)
|
||||
$cache_manager->set_blocked_doctors([999]);
|
||||
$cache_manager->set_blocked_doctors([998]);
|
||||
$cache_manager->set_blocked_doctors([997]);
|
||||
|
||||
// Last write should win
|
||||
$final_data = $cache_manager->get_blocked_doctors();
|
||||
$this->assertEquals([997], $final_data, 'Last cache write should be preserved');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* Descomplicar® Crescimento Digital
|
||||
* https://descomplicar.pt
|
||||
*/
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Database schema tests for Care Booking Block plugin
|
||||
*
|
||||
* @package CareBookingBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test database schema creation and structure
|
||||
*/
|
||||
class Test_Database_Schema extends Care_Booking_Test_Case
|
||||
{
|
||||
|
||||
/**
|
||||
* Test that wp_care_booking_restrictions table exists
|
||||
*/
|
||||
public function test_restrictions_table_exists()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
$table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
|
||||
|
||||
$this->assertTrue($table_exists, 'wp_care_booking_restrictions table should exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test table has required columns with correct types
|
||||
*/
|
||||
public function test_table_has_correct_columns()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
$columns = $wpdb->get_results("DESCRIBE $table_name");
|
||||
|
||||
// Convert to associative array for easier testing
|
||||
$column_data = [];
|
||||
foreach ($columns as $column) {
|
||||
$column_data[$column->Field] = [
|
||||
'Type' => $column->Type,
|
||||
'Null' => $column->Null,
|
||||
'Key' => $column->Key,
|
||||
'Default' => $column->Default,
|
||||
'Extra' => $column->Extra
|
||||
];
|
||||
}
|
||||
|
||||
// Test required columns exist
|
||||
$expected_columns = ['id', 'restriction_type', 'target_id', 'doctor_id', 'is_blocked', 'created_at', 'updated_at'];
|
||||
foreach ($expected_columns as $column) {
|
||||
$this->assertArrayHasKey($column, $column_data, "Column '$column' should exist");
|
||||
}
|
||||
|
||||
// Test column types
|
||||
$this->assertEquals('bigint(20) unsigned', $column_data['id']['Type']);
|
||||
$this->assertEquals("enum('doctor','service')", $column_data['restriction_type']['Type']);
|
||||
$this->assertEquals('bigint(20) unsigned', $column_data['target_id']['Type']);
|
||||
$this->assertEquals('bigint(20) unsigned', $column_data['doctor_id']['Type']);
|
||||
$this->assertEquals('tinyint(1)', $column_data['is_blocked']['Type']);
|
||||
$this->assertEquals('timestamp', $column_data['created_at']['Type']);
|
||||
$this->assertEquals('timestamp', $column_data['updated_at']['Type']);
|
||||
|
||||
// Test primary key
|
||||
$this->assertEquals('PRI', $column_data['id']['Key']);
|
||||
$this->assertEquals('auto_increment', $column_data['id']['Extra']);
|
||||
|
||||
// Test null constraints
|
||||
$this->assertEquals('NO', $column_data['id']['Null']);
|
||||
$this->assertEquals('NO', $column_data['restriction_type']['Null']);
|
||||
$this->assertEquals('NO', $column_data['target_id']['Null']);
|
||||
$this->assertEquals('YES', $column_data['doctor_id']['Null']);
|
||||
$this->assertEquals('NO', $column_data['is_blocked']['Null']);
|
||||
|
||||
// Test default values
|
||||
$this->assertEquals('0', $column_data['is_blocked']['Default']);
|
||||
$this->assertEquals('current_timestamp()', $column_data['created_at']['Default']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test table has required indexes
|
||||
*/
|
||||
public function test_table_has_required_indexes()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
$indexes = $wpdb->get_results("SHOW INDEX FROM $table_name");
|
||||
|
||||
// Convert to associative array for easier testing
|
||||
$index_data = [];
|
||||
foreach ($indexes as $index) {
|
||||
$index_data[$index->Key_name][] = $index->Column_name;
|
||||
}
|
||||
|
||||
// Test required indexes exist
|
||||
$this->assertArrayHasKey('PRIMARY', $index_data, 'PRIMARY index should exist');
|
||||
$this->assertArrayHasKey('idx_type_target', $index_data, 'idx_type_target index should exist');
|
||||
$this->assertArrayHasKey('idx_doctor_service', $index_data, 'idx_doctor_service index should exist');
|
||||
$this->assertArrayHasKey('idx_blocked', $index_data, 'idx_blocked index should exist');
|
||||
|
||||
// Test index columns
|
||||
$this->assertEquals(['id'], $index_data['PRIMARY']);
|
||||
$this->assertEquals(['restriction_type', 'target_id'], $index_data['idx_type_target']);
|
||||
$this->assertEquals(['doctor_id', 'target_id'], $index_data['idx_doctor_service']);
|
||||
$this->assertEquals(['is_blocked'], $index_data['idx_blocked']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test enum constraint on restriction_type
|
||||
*/
|
||||
public function test_restriction_type_enum_constraint()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
|
||||
// Test valid enum values
|
||||
$valid_insert = $wpdb->insert(
|
||||
$table_name,
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => 1
|
||||
]
|
||||
);
|
||||
$this->assertNotFalse($valid_insert, 'Should insert valid restriction_type');
|
||||
|
||||
// Clean up
|
||||
$wpdb->delete($table_name, ['target_id' => 999]);
|
||||
|
||||
// Test invalid enum values (this should fail)
|
||||
$invalid_insert = $wpdb->insert(
|
||||
$table_name,
|
||||
[
|
||||
'restriction_type' => 'invalid_type',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => 1
|
||||
]
|
||||
);
|
||||
$this->assertFalse($invalid_insert, 'Should not insert invalid restriction_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test auto-increment behavior on id field
|
||||
*/
|
||||
public function test_auto_increment_id_field()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
|
||||
// Insert first record
|
||||
$result1 = $wpdb->insert(
|
||||
$table_name,
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => 1
|
||||
]
|
||||
);
|
||||
$this->assertNotFalse($result1);
|
||||
$id1 = $wpdb->insert_id;
|
||||
|
||||
// Insert second record
|
||||
$result2 = $wpdb->insert(
|
||||
$table_name,
|
||||
[
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 998,
|
||||
'doctor_id' => 999,
|
||||
'is_blocked' => 1
|
||||
]
|
||||
);
|
||||
$this->assertNotFalse($result2);
|
||||
$id2 = $wpdb->insert_id;
|
||||
|
||||
// Test auto-increment
|
||||
$this->assertGreaterThan($id1, $id2, 'Second ID should be greater than first');
|
||||
|
||||
// Clean up
|
||||
$wpdb->delete($table_name, ['target_id' => 999]);
|
||||
$wpdb->delete($table_name, ['target_id' => 998]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test timestamp fields behavior
|
||||
*/
|
||||
public function test_timestamp_fields()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
|
||||
// Insert record and check timestamps
|
||||
$before_insert = current_time('mysql');
|
||||
|
||||
$result = $wpdb->insert(
|
||||
$table_name,
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => 1
|
||||
]
|
||||
);
|
||||
$this->assertNotFalse($result);
|
||||
|
||||
$after_insert = current_time('mysql');
|
||||
|
||||
// Get the inserted record
|
||||
$record = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE target_id = %d", 999));
|
||||
$this->assertNotNull($record);
|
||||
|
||||
// Test created_at is set automatically
|
||||
$this->assertNotNull($record->created_at);
|
||||
$this->assertGreaterThanOrEqual($before_insert, $record->created_at);
|
||||
$this->assertLessThanOrEqual($after_insert, $record->created_at);
|
||||
|
||||
// Test updated_at matches created_at on insert
|
||||
$this->assertEquals($record->created_at, $record->updated_at);
|
||||
|
||||
// Wait a moment and update record
|
||||
sleep(1);
|
||||
$before_update = current_time('mysql');
|
||||
|
||||
$wpdb->update(
|
||||
$table_name,
|
||||
['is_blocked' => 0],
|
||||
['target_id' => 999]
|
||||
);
|
||||
|
||||
$after_update = current_time('mysql');
|
||||
|
||||
// Get updated record
|
||||
$updated_record = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE target_id = %d", 999));
|
||||
|
||||
// Test updated_at changed automatically
|
||||
$this->assertNotEquals($record->updated_at, $updated_record->updated_at);
|
||||
$this->assertGreaterThanOrEqual($before_update, $updated_record->updated_at);
|
||||
$this->assertLessThanOrEqual($after_update, $updated_record->updated_at);
|
||||
|
||||
// Test created_at remained unchanged
|
||||
$this->assertEquals($record->created_at, $updated_record->created_at);
|
||||
|
||||
// Clean up
|
||||
$wpdb->delete($table_name, ['target_id' => 999]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database table cleanup on plugin deactivation
|
||||
*/
|
||||
public function test_plugin_deactivation_preserves_data()
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'care_booking_restrictions';
|
||||
|
||||
// Insert test data
|
||||
$wpdb->insert(
|
||||
$table_name,
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => 1
|
||||
]
|
||||
);
|
||||
|
||||
// Simulate plugin deactivation
|
||||
$plugin = CareBookingBlock::get_instance();
|
||||
$plugin->deactivate();
|
||||
|
||||
// Check that table and data still exist
|
||||
$table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
|
||||
$this->assertTrue($table_exists, 'Table should still exist after deactivation');
|
||||
|
||||
$record_exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE target_id = %d", 999));
|
||||
$this->assertEquals('1', $record_exists, 'Data should be preserved after deactivation');
|
||||
|
||||
// Clean up
|
||||
$wpdb->delete($table_name, ['target_id' => 999]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* Descomplicar® Crescimento Digital
|
||||
* https://descomplicar.pt
|
||||
*/
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Restriction model CRUD tests for Care Booking Block plugin
|
||||
*
|
||||
* @package CareBookingBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test restriction model CRUD operations
|
||||
*/
|
||||
class Test_Restriction_Model extends Care_Booking_Test_Case
|
||||
{
|
||||
|
||||
/**
|
||||
* Test restriction model class exists and can be instantiated
|
||||
*/
|
||||
public function test_restriction_model_class_exists()
|
||||
{
|
||||
$this->assertTrue(class_exists('Care_Booking_Restriction_Model'), 'Care_Booking_Restriction_Model class should exist');
|
||||
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
$this->assertInstanceOf('Care_Booking_Restriction_Model', $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create doctor restriction
|
||||
*/
|
||||
public function test_create_doctor_restriction()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
$restriction_data = [
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
];
|
||||
|
||||
$restriction_id = $model->create($restriction_data);
|
||||
$this->assertIsInt($restriction_id, 'Should return integer restriction ID');
|
||||
$this->assertGreaterThan(0, $restriction_id, 'Restriction ID should be greater than 0');
|
||||
|
||||
// Verify restriction was created in database
|
||||
$created_restriction = $model->get($restriction_id);
|
||||
$this->assertNotFalse($created_restriction, 'Should retrieve created restriction');
|
||||
$this->assertEquals('doctor', $created_restriction->restriction_type);
|
||||
$this->assertEquals(999, $created_restriction->target_id);
|
||||
$this->assertNull($created_restriction->doctor_id);
|
||||
$this->assertEquals(1, $created_restriction->is_blocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create service restriction
|
||||
*/
|
||||
public function test_create_service_restriction()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
$restriction_data = [
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 888,
|
||||
'doctor_id' => 999,
|
||||
'is_blocked' => true
|
||||
];
|
||||
|
||||
$restriction_id = $model->create($restriction_data);
|
||||
$this->assertIsInt($restriction_id);
|
||||
$this->assertGreaterThan(0, $restriction_id);
|
||||
|
||||
// Verify restriction was created
|
||||
$created_restriction = $model->get($restriction_id);
|
||||
$this->assertEquals('service', $created_restriction->restriction_type);
|
||||
$this->assertEquals(888, $created_restriction->target_id);
|
||||
$this->assertEquals(999, $created_restriction->doctor_id);
|
||||
$this->assertEquals(1, $created_restriction->is_blocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read restriction by ID
|
||||
*/
|
||||
public function test_read_restriction_by_id()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create test restriction
|
||||
$restriction_id = $this->create_test_doctor_restriction(999, true);
|
||||
$this->assertNotFalse($restriction_id);
|
||||
|
||||
// Read restriction
|
||||
$restriction = $model->get($restriction_id);
|
||||
$this->assertNotFalse($restriction, 'Should retrieve restriction by ID');
|
||||
$this->assertEquals($restriction_id, $restriction->id);
|
||||
$this->assertEquals('doctor', $restriction->restriction_type);
|
||||
$this->assertEquals(999, $restriction->target_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get restrictions by type
|
||||
*/
|
||||
public function test_get_restrictions_by_type()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create test restrictions
|
||||
$this->create_test_doctor_restriction(999, true);
|
||||
$this->create_test_doctor_restriction(998, false);
|
||||
$this->create_test_service_restriction(888, 999, true);
|
||||
|
||||
// Get doctor restrictions
|
||||
$doctor_restrictions = $model->get_by_type('doctor');
|
||||
$this->assertIsArray($doctor_restrictions, 'Should return array of doctor restrictions');
|
||||
$this->assertCount(2, $doctor_restrictions, 'Should return 2 doctor restrictions');
|
||||
|
||||
// Verify all are doctor type
|
||||
foreach ($doctor_restrictions as $restriction) {
|
||||
$this->assertEquals('doctor', $restriction->restriction_type);
|
||||
}
|
||||
|
||||
// Get service restrictions
|
||||
$service_restrictions = $model->get_by_type('service');
|
||||
$this->assertIsArray($service_restrictions);
|
||||
$this->assertCount(1, $service_restrictions, 'Should return 1 service restriction');
|
||||
$this->assertEquals('service', $service_restrictions[0]->restriction_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get blocked doctors
|
||||
*/
|
||||
public function test_get_blocked_doctors()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create test restrictions
|
||||
$this->create_test_doctor_restriction(999, true); // Blocked
|
||||
$this->create_test_doctor_restriction(998, false); // Not blocked
|
||||
$this->create_test_doctor_restriction(997, true); // Blocked
|
||||
|
||||
$blocked_doctors = $model->get_blocked_doctors();
|
||||
$this->assertIsArray($blocked_doctors, 'Should return array of blocked doctor IDs');
|
||||
$this->assertCount(2, $blocked_doctors, 'Should return 2 blocked doctors');
|
||||
|
||||
// Check that correct doctors are blocked
|
||||
$this->assertContains(999, $blocked_doctors);
|
||||
$this->assertContains(997, $blocked_doctors);
|
||||
$this->assertNotContains(998, $blocked_doctors, 'Non-blocked doctor should not be in list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get blocked services for specific doctor
|
||||
*/
|
||||
public function test_get_blocked_services_by_doctor()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create test service restrictions for doctor 999
|
||||
$this->create_test_service_restriction(888, 999, true); // Blocked
|
||||
$this->create_test_service_restriction(887, 999, false); // Not blocked
|
||||
$this->create_test_service_restriction(886, 998, true); // Different doctor
|
||||
|
||||
$blocked_services = $model->get_blocked_services(999);
|
||||
$this->assertIsArray($blocked_services);
|
||||
$this->assertCount(1, $blocked_services, 'Should return 1 blocked service for doctor 999');
|
||||
$this->assertContains(888, $blocked_services);
|
||||
$this->assertNotContains(887, $blocked_services, 'Non-blocked service should not be in list');
|
||||
$this->assertNotContains(886, $blocked_services, 'Service for different doctor should not be in list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update restriction
|
||||
*/
|
||||
public function test_update_restriction()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create test restriction
|
||||
$restriction_id = $this->create_test_doctor_restriction(999, true);
|
||||
|
||||
// Update restriction
|
||||
$update_data = ['is_blocked' => false];
|
||||
$result = $model->update($restriction_id, $update_data);
|
||||
$this->assertTrue($result, 'Update should return true on success');
|
||||
|
||||
// Verify update
|
||||
$updated_restriction = $model->get($restriction_id);
|
||||
$this->assertEquals(0, $updated_restriction->is_blocked, 'is_blocked should be updated to false');
|
||||
|
||||
// Verify updated_at timestamp changed
|
||||
$this->assertNotNull($updated_restriction->updated_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete restriction
|
||||
*/
|
||||
public function test_delete_restriction()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create test restriction
|
||||
$restriction_id = $this->create_test_doctor_restriction(999, true);
|
||||
|
||||
// Verify restriction exists
|
||||
$restriction = $model->get($restriction_id);
|
||||
$this->assertNotFalse($restriction);
|
||||
|
||||
// Delete restriction
|
||||
$result = $model->delete($restriction_id);
|
||||
$this->assertTrue($result, 'Delete should return true on success');
|
||||
|
||||
// Verify restriction no longer exists
|
||||
$deleted_restriction = $model->get($restriction_id);
|
||||
$this->assertFalse($deleted_restriction, 'Restriction should not exist after deletion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test find existing restriction
|
||||
*/
|
||||
public function test_find_existing_restriction()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Create doctor restriction
|
||||
$doctor_restriction_id = $this->create_test_doctor_restriction(999, true);
|
||||
|
||||
// Find existing doctor restriction
|
||||
$found_doctor = $model->find_existing('doctor', 999);
|
||||
$this->assertNotFalse($found_doctor, 'Should find existing doctor restriction');
|
||||
$this->assertEquals($doctor_restriction_id, $found_doctor->id);
|
||||
|
||||
// Create service restriction
|
||||
$service_restriction_id = $this->create_test_service_restriction(888, 999, true);
|
||||
|
||||
// Find existing service restriction
|
||||
$found_service = $model->find_existing('service', 888, 999);
|
||||
$this->assertNotFalse($found_service, 'Should find existing service restriction');
|
||||
$this->assertEquals($service_restriction_id, $found_service->id);
|
||||
|
||||
// Try to find non-existing restriction
|
||||
$not_found = $model->find_existing('doctor', 123);
|
||||
$this->assertFalse($not_found, 'Should return false for non-existing restriction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test toggle restriction (create or update)
|
||||
*/
|
||||
public function test_toggle_restriction()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Toggle non-existing restriction (should create)
|
||||
$result = $model->toggle('doctor', 999, null, true);
|
||||
$this->assertIsInt($result, 'Should return restriction ID when creating');
|
||||
|
||||
// Verify restriction was created
|
||||
$restriction = $model->find_existing('doctor', 999);
|
||||
$this->assertNotFalse($restriction);
|
||||
$this->assertEquals(1, $restriction->is_blocked);
|
||||
|
||||
// Toggle existing restriction (should update)
|
||||
$result2 = $model->toggle('doctor', 999, null, false);
|
||||
$this->assertTrue($result2, 'Should return true when updating existing');
|
||||
|
||||
// Verify restriction was updated
|
||||
$updated_restriction = $model->find_existing('doctor', 999);
|
||||
$this->assertEquals(0, $updated_restriction->is_blocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validation errors
|
||||
*/
|
||||
public function test_validation_errors()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
// Test invalid restriction type
|
||||
$invalid_data = [
|
||||
'restriction_type' => 'invalid',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
];
|
||||
|
||||
$result = $model->create($invalid_data);
|
||||
$this->assertFalse($result, 'Should return false for invalid restriction type');
|
||||
|
||||
// Test missing target_id
|
||||
$invalid_data2 = [
|
||||
'restriction_type' => 'doctor',
|
||||
'is_blocked' => true
|
||||
];
|
||||
|
||||
$result2 = $model->create($invalid_data2);
|
||||
$this->assertFalse($result2, 'Should return false for missing target_id');
|
||||
|
||||
// Test service restriction without doctor_id
|
||||
$invalid_data3 = [
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 888,
|
||||
'is_blocked' => true
|
||||
];
|
||||
|
||||
$result3 = $model->create($invalid_data3);
|
||||
$this->assertFalse($result3, 'Should return false for service restriction without doctor_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test bulk operations
|
||||
*/
|
||||
public function test_bulk_operations()
|
||||
{
|
||||
$model = new Care_Booking_Restriction_Model();
|
||||
|
||||
$bulk_data = [
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 999,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'doctor',
|
||||
'target_id' => 998,
|
||||
'is_blocked' => true
|
||||
],
|
||||
[
|
||||
'restriction_type' => 'service',
|
||||
'target_id' => 888,
|
||||
'doctor_id' => 999,
|
||||
'is_blocked' => false
|
||||
]
|
||||
];
|
||||
|
||||
$results = $model->bulk_create($bulk_data);
|
||||
$this->assertIsArray($results, 'Should return array of results');
|
||||
$this->assertCount(3, $results, 'Should return 3 results');
|
||||
|
||||
// Verify all were created successfully
|
||||
foreach ($results as $result) {
|
||||
$this->assertIsInt($result, 'Each result should be a restriction ID');
|
||||
$this->assertGreaterThan(0, $result);
|
||||
}
|
||||
|
||||
// Verify restrictions exist
|
||||
$doctor_restrictions = $model->get_by_type('doctor');
|
||||
$this->assertCount(2, $doctor_restrictions);
|
||||
|
||||
$service_restrictions = $model->get_by_type('service');
|
||||
$this->assertCount(1, $service_restrictions);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user