- 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>
374 lines
14 KiB
PHP
374 lines
14 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
/**
|
|
* Integration test for frontend JavaScript graceful degradation (T032)
|
|
*
|
|
* @package CareBookingBlock
|
|
*/
|
|
|
|
/**
|
|
* Test frontend JavaScript enqueuing and configuration
|
|
*/
|
|
class Test_Frontend_JavaScript extends Care_Booking_Test_Case
|
|
{
|
|
/**
|
|
* Test frontend scripts are enqueued on appropriate pages
|
|
*/
|
|
public function test_frontend_scripts_enqueued()
|
|
{
|
|
// Mock KiviCare as active
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare_booking]'
|
|
];
|
|
|
|
$integration = $this->plugin->kivicare_integration;
|
|
|
|
// Trigger script enqueuing
|
|
do_action('wp_enqueue_scripts');
|
|
|
|
// Check if script is registered
|
|
$this->assertTrue(wp_script_is('care-booking-frontend', 'registered'),
|
|
'Frontend script should be registered');
|
|
|
|
// Note: wp_script_is('enqueued') might not work in test environment
|
|
// as it depends on KiviCare being active and page content detection
|
|
}
|
|
|
|
/**
|
|
* Test script localization with correct configuration
|
|
*/
|
|
public function test_script_localization()
|
|
{
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare]'
|
|
];
|
|
|
|
$integration = $this->plugin->kivicare_integration;
|
|
|
|
// Mock wp_localize_script to capture data
|
|
$localized_data = null;
|
|
|
|
add_filter('wp_localize_script_care-booking-frontend_careBookingConfig', function($data) use (&$localized_data) {
|
|
$localized_data = $data;
|
|
return $data;
|
|
});
|
|
|
|
// Trigger script enqueuing
|
|
do_action('wp_enqueue_scripts');
|
|
|
|
// If script was enqueued and localized, check the data
|
|
if ($localized_data) {
|
|
$this->assertArrayHasKey('ajaxurl', $localized_data, 'Should include AJAX URL');
|
|
$this->assertArrayHasKey('nonce', $localized_data, 'Should include nonce');
|
|
$this->assertArrayHasKey('debug', $localized_data, 'Should include debug flag');
|
|
$this->assertArrayHasKey('fallbackEnabled', $localized_data, 'Should include fallback flag');
|
|
$this->assertArrayHasKey('retryAttempts', $localized_data, 'Should include retry attempts');
|
|
$this->assertArrayHasKey('selectors', $localized_data, 'Should include selectors');
|
|
|
|
// Check selectors structure
|
|
$this->assertArrayHasKey('doctors', $localized_data['selectors'], 'Should include doctor selectors');
|
|
$this->assertArrayHasKey('services', $localized_data['selectors'], 'Should include service selectors');
|
|
$this->assertArrayHasKey('forms', $localized_data['selectors'], 'Should include form selectors');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test should_load_frontend_scripts logic
|
|
*/
|
|
public function test_should_load_frontend_scripts_logic()
|
|
{
|
|
$integration = $this->plugin->kivicare_integration;
|
|
|
|
// Use reflection to access private method
|
|
$reflection = new ReflectionClass($integration);
|
|
$method = $reflection->getMethod('should_load_frontend_scripts');
|
|
$method->setAccessible(true);
|
|
|
|
global $post;
|
|
|
|
// Test with KiviCare shortcode
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => 'Some content [kivicare] more content'
|
|
];
|
|
|
|
$should_load = $method->invoke($integration);
|
|
$this->assertTrue($should_load, 'Should load scripts on pages with kivicare shortcode');
|
|
|
|
// Test with KiviCare block
|
|
$post = (object) [
|
|
'ID' => 124,
|
|
'post_content' => '<!-- wp:kivicare/booking --><div>Booking form</div><!-- /wp:kivicare/booking -->'
|
|
];
|
|
|
|
$should_load = $method->invoke($integration);
|
|
$this->assertTrue($should_load, 'Should load scripts on pages with kivicare block');
|
|
|
|
// Test with regular content
|
|
$post = (object) [
|
|
'ID' => 125,
|
|
'post_content' => 'Regular page content without KiviCare'
|
|
];
|
|
|
|
$should_load = $method->invoke($integration);
|
|
$this->assertFalse($should_load, 'Should not load scripts on regular pages');
|
|
|
|
// Test with URL parameters
|
|
$_GET['kivicare'] = '1';
|
|
$should_load = $method->invoke($integration);
|
|
$this->assertTrue($should_load, 'Should load scripts when URL contains kivicare parameter');
|
|
unset($_GET['kivicare']);
|
|
|
|
$_GET['booking'] = '1';
|
|
$should_load = $method->invoke($integration);
|
|
$this->assertTrue($should_load, 'Should load scripts when URL contains booking parameter');
|
|
unset($_GET['booking']);
|
|
}
|
|
|
|
/**
|
|
* Test frontend script file exists and has correct content structure
|
|
*/
|
|
public function test_frontend_script_file_structure()
|
|
{
|
|
$script_path = CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.js';
|
|
|
|
$this->assertFileExists($script_path, 'Frontend JavaScript file should exist');
|
|
|
|
$script_content = file_get_contents($script_path);
|
|
|
|
// Check for main structure
|
|
$this->assertStringContainsString('CareBooking', $script_content,
|
|
'Should contain CareBooking object');
|
|
$this->assertStringContainsString('init:', $script_content,
|
|
'Should contain init method');
|
|
$this->assertStringContainsString('setupObservers:', $script_content,
|
|
'Should contain setupObservers method');
|
|
$this->assertStringContainsString('enhanceExistingElements:', $script_content,
|
|
'Should contain enhanceExistingElements method');
|
|
|
|
// Check for graceful degradation features
|
|
$this->assertStringContainsString('setupFallbacks:', $script_content,
|
|
'Should contain setupFallbacks method');
|
|
$this->assertStringContainsString('MutationObserver', $script_content,
|
|
'Should use MutationObserver for dynamic content');
|
|
$this->assertStringContainsString('ajaxError', $script_content,
|
|
'Should handle AJAX errors');
|
|
|
|
// Check for validation features
|
|
$this->assertStringContainsString('validateBookingForm:', $script_content,
|
|
'Should contain form validation');
|
|
$this->assertStringContainsString('showLoadingState:', $script_content,
|
|
'Should contain loading state management');
|
|
|
|
// Check for offline detection
|
|
$this->assertStringContainsString('online offline', $script_content,
|
|
'Should handle online/offline events');
|
|
}
|
|
|
|
/**
|
|
* Test script dependencies are correct
|
|
*/
|
|
public function test_script_dependencies()
|
|
{
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare]'
|
|
];
|
|
|
|
// Trigger script enqueuing
|
|
do_action('wp_enqueue_scripts');
|
|
|
|
// Check if jQuery is a dependency
|
|
global $wp_scripts;
|
|
|
|
if (isset($wp_scripts->registered['care-booking-frontend'])) {
|
|
$script = $wp_scripts->registered['care-booking-frontend'];
|
|
$this->assertContains('jquery', $script->deps, 'Should depend on jQuery');
|
|
$this->assertEquals(CARE_BOOKING_BLOCK_VERSION, $script->ver, 'Should use plugin version');
|
|
$this->assertTrue($script->extra['in_footer'], 'Should load in footer');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test script configuration values
|
|
*/
|
|
public function test_script_configuration_values()
|
|
{
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare]'
|
|
];
|
|
|
|
$integration = $this->plugin->kivicare_integration;
|
|
|
|
// Capture localized data
|
|
$captured_data = null;
|
|
|
|
// Mock wp_localize_script
|
|
add_filter('wp_scripts_print_extra_script', function($output, $handle) use (&$captured_data) {
|
|
if ($handle === 'care-booking-frontend') {
|
|
// Extract config from JavaScript
|
|
if (preg_match('/careBookingConfig\s*=\s*({.+?});/', $output, $matches)) {
|
|
$captured_data = json_decode($matches[1], true);
|
|
}
|
|
}
|
|
return $output;
|
|
}, 10, 2);
|
|
|
|
// Trigger script enqueuing
|
|
do_action('wp_enqueue_scripts');
|
|
|
|
// If we captured data, validate it
|
|
if ($captured_data) {
|
|
// Check AJAX URL
|
|
$this->assertStringContainsString('admin-ajax.php', $captured_data['ajaxurl'],
|
|
'AJAX URL should point to admin-ajax.php');
|
|
|
|
// Check nonce is valid
|
|
$this->assertTrue(wp_verify_nonce($captured_data['nonce'], 'care_booking_frontend'),
|
|
'Nonce should be valid');
|
|
|
|
// Check boolean values
|
|
$this->assertIsBool($captured_data['debug'], 'Debug should be boolean');
|
|
$this->assertIsBool($captured_data['fallbackEnabled'], 'Fallback should be boolean');
|
|
|
|
// Check numeric values
|
|
$this->assertIsNumeric($captured_data['retryAttempts'], 'Retry attempts should be numeric');
|
|
$this->assertIsNumeric($captured_data['retryDelay'], 'Retry delay should be numeric');
|
|
$this->assertGreaterThan(0, $captured_data['retryAttempts'], 'Should have positive retry attempts');
|
|
$this->assertGreaterThan(0, $captured_data['retryDelay'], 'Should have positive retry delay');
|
|
|
|
// Check selectors
|
|
$this->assertIsArray($captured_data['selectors'], 'Selectors should be array');
|
|
$this->assertArrayHasKey('doctors', $captured_data['selectors']);
|
|
$this->assertArrayHasKey('services', $captured_data['selectors']);
|
|
$this->assertArrayHasKey('forms', $captured_data['selectors']);
|
|
|
|
// Check selector format
|
|
$this->assertStringContainsString('.kivicare-doctor', $captured_data['selectors']['doctors'],
|
|
'Doctor selectors should include .kivicare-doctor');
|
|
$this->assertStringContainsString('.kivicare-service', $captured_data['selectors']['services'],
|
|
'Service selectors should include .kivicare-service');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test script only loads when KiviCare is active
|
|
*/
|
|
public function test_script_kivicare_dependency()
|
|
{
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare]'
|
|
];
|
|
|
|
$integration = $this->plugin->kivicare_integration;
|
|
|
|
// Mock KiviCare as inactive
|
|
$reflection = new ReflectionClass($integration);
|
|
$method = $reflection->getMethod('is_kivicare_active');
|
|
$method->setAccessible(true);
|
|
|
|
// The method checks for actual plugin files, so in test environment
|
|
// it will likely return false, which is correct behavior
|
|
|
|
// Trigger script enqueuing
|
|
do_action('wp_enqueue_scripts');
|
|
|
|
// Script should not be enqueued if KiviCare is not active
|
|
// This is mainly to test the logic path doesn't cause errors
|
|
$this->assertTrue(true, 'Script enqueuing should handle inactive KiviCare gracefully');
|
|
}
|
|
|
|
/**
|
|
* Test admin area script exclusion
|
|
*/
|
|
public function test_admin_area_script_exclusion()
|
|
{
|
|
// Mock admin area
|
|
set_current_screen('edit-post');
|
|
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare]'
|
|
];
|
|
|
|
// Trigger script enqueuing
|
|
do_action('wp_enqueue_scripts');
|
|
|
|
// Script should not be enqueued in admin area
|
|
$this->assertFalse(wp_script_is('care-booking-frontend', 'enqueued'),
|
|
'Frontend script should not be enqueued in admin area');
|
|
}
|
|
|
|
/**
|
|
* Test script file is minified in production
|
|
*/
|
|
public function test_script_optimization()
|
|
{
|
|
$script_path = CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.js';
|
|
$script_content = file_get_contents($script_path);
|
|
|
|
// In development, script should be readable
|
|
if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
$this->assertGreaterThan(100, substr_count($script_content, "\n"),
|
|
'Development script should have line breaks');
|
|
$this->assertStringContainsString(' ', $script_content,
|
|
'Development script should have indentation');
|
|
}
|
|
|
|
// Script should have proper structure regardless of minification
|
|
$this->assertStringContainsString('CareBooking', $script_content,
|
|
'Script should contain CareBooking object');
|
|
$this->assertStringContainsString('jQuery', $script_content,
|
|
'Script should reference jQuery');
|
|
}
|
|
|
|
/**
|
|
* Test error handling in script enqueuing
|
|
*/
|
|
public function test_script_enqueuing_error_handling()
|
|
{
|
|
global $post;
|
|
$post = (object) [
|
|
'ID' => 123,
|
|
'post_content' => '[kivicare]'
|
|
];
|
|
|
|
// Mock file not found scenario by temporarily renaming the file
|
|
$script_path = CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.js';
|
|
$temp_path = CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.js.temp';
|
|
|
|
if (file_exists($script_path)) {
|
|
rename($script_path, $temp_path);
|
|
}
|
|
|
|
// Trigger script enqueuing - should not cause fatal errors
|
|
ob_start();
|
|
do_action('wp_enqueue_scripts');
|
|
$output = ob_get_clean();
|
|
|
|
// Restore file
|
|
if (file_exists($temp_path)) {
|
|
rename($temp_path, $script_path);
|
|
}
|
|
|
|
// Should not produce PHP errors
|
|
$this->assertStringNotContainsString('Fatal error', $output,
|
|
'Should handle missing script file gracefully');
|
|
$this->assertStringNotContainsString('Warning:', $output,
|
|
'Should handle missing script file without warnings');
|
|
}
|
|
} |