upskill-event-manager/tests/unit/test-announcements-display.php
ben 80f11e71dd fix: resolve dashboard fatal errors and event edit security check failures
Fixes three critical production issues discovered on upskillhvac.com:

 Dashboard Fatal Errors (class-hvac-dashboard-data.php):
- Added class_exists('Tribe__Events__Main') checks before accessing TEC constants
- Prevents fatal errors when TEC plugin loads after our code
- Applied to get_total_events_count(), get_upcoming_events_count(), and get_past_events_count()
- Gracefully returns 0 when TEC is not available

 Event Edit Security Check Failure (page-edit-event-custom.php):
- Fixed nonce action mismatch: changed 'hvac_edit_event' to 'hvac_event_action'
- Aligns with HVAC_Event_Manager::NONCE_ACTION constant
- Resolves "Security check failed" error on event update forms

 Google Drive Folder Update:
- Updated embedded folder ID from 16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG to 1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs
- Applied to templates/page-trainer-resources.php (trainer resources page)
- Applied to includes/class-hvac-announcements-display.php (shortcode default)
- Updated tests/unit/test-announcements-display.php (test references)

All changes tested and verified on production.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 16:37:59 -03:00

281 lines
No EOL
10 KiB
PHP

<?php
/**
* Unit Tests for HVAC Announcements Display Handler
*
* @package HVAC_Community_Events
* @subpackage Tests
*/
class Test_HVAC_Announcements_Display extends WP_UnitTestCase {
/**
* Test users
*/
private $master_trainer;
private $regular_trainer;
/**
* Test announcements
*/
private $test_announcements = array();
/**
* Display handler instance
*/
private $display_handler;
/**
* Setup before each test
*/
public function setUp() {
parent::setUp();
// Create test users
$this->master_trainer = $this->factory->user->create( array(
'role' => 'hvac_master_trainer',
'user_login' => 'master_trainer',
'user_email' => 'master@example.com',
) );
$this->regular_trainer = $this->factory->user->create( array(
'role' => 'hvac_trainer',
'user_login' => 'regular_trainer',
'user_email' => 'trainer@example.com',
) );
// Add capabilities
HVAC_Announcements_Permissions::add_capabilities();
// Create test announcements with different statuses
$this->test_announcements['published'] = wp_insert_post( array(
'post_type' => HVAC_Announcements_CPT::get_post_type(),
'post_title' => 'Published Announcement',
'post_content' => 'This is published content.',
'post_excerpt' => 'Published excerpt',
'post_status' => 'publish',
'post_author' => $this->master_trainer,
) );
$this->test_announcements['draft'] = wp_insert_post( array(
'post_type' => HVAC_Announcements_CPT::get_post_type(),
'post_title' => 'Draft Announcement',
'post_content' => 'This is draft content.',
'post_status' => 'draft',
'post_author' => $this->master_trainer,
) );
// Get display handler instance
$this->display_handler = HVAC_Announcements_Display::get_instance();
}
/**
* Teardown after each test
*/
public function tearDown() {
parent::tearDown();
// Clean up test announcements
foreach ( $this->test_announcements as $post_id ) {
wp_delete_post( $post_id, true );
}
// Clean up test users
wp_delete_user( $this->master_trainer );
wp_delete_user( $this->regular_trainer );
// Remove capabilities
HVAC_Announcements_Permissions::remove_capabilities();
}
/**
* Test shortcode registration
*/
public function test_shortcodes_registered() {
global $shortcode_tags;
$this->assertArrayHasKey( 'hvac_announcements_timeline', $shortcode_tags );
$this->assertArrayHasKey( 'hvac_announcements_list', $shortcode_tags );
$this->assertArrayHasKey( 'hvac_google_drive_embed', $shortcode_tags );
}
/**
* Test timeline shortcode output for authorized user
*/
public function test_timeline_shortcode_authorized() {
wp_set_current_user( $this->regular_trainer );
$output = do_shortcode( '[hvac_announcements_timeline posts_per_page="5"]' );
// Should contain the wrapper div
$this->assertStringContainsString( 'hvac-announcements-timeline', $output );
// Should contain the published announcement
$this->assertStringContainsString( 'Published Announcement', $output );
// Should NOT contain draft announcement for regular trainer
$this->assertStringNotContainsString( 'Draft Announcement', $output );
// Should contain modal structure
$this->assertStringContainsString( 'announcement-modal', $output );
}
/**
* Test timeline shortcode output for unauthorized user
*/
public function test_timeline_shortcode_unauthorized() {
// Create non-trainer user
$subscriber = $this->factory->user->create( array(
'role' => 'subscriber',
) );
wp_set_current_user( $subscriber );
$output = do_shortcode( '[hvac_announcements_timeline]' );
// Should show permission denied message
$this->assertStringContainsString( 'You do not have permission to view announcements', $output );
// Clean up
wp_delete_user( $subscriber );
}
/**
* Test list shortcode attributes
*/
public function test_list_shortcode_attributes() {
wp_set_current_user( $this->regular_trainer );
// Test with show_excerpt="no"
$output = do_shortcode( '[hvac_announcements_list show_excerpt="no" show_date="yes"]' );
// Should contain the list wrapper
$this->assertStringContainsString( 'hvac-announcements-list', $output );
// Should contain announcement title
$this->assertStringContainsString( 'Published Announcement', $output );
}
/**
* Test Google Drive embed shortcode
*/
public function test_google_drive_shortcode() {
wp_set_current_user( $this->regular_trainer );
$output = do_shortcode( '[hvac_google_drive_embed url="https://drive.google.com/drive/folders/1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs" height="500"]' );
// Should contain iframe
$this->assertStringContainsString( '<iframe', $output );
$this->assertStringContainsString( 'height="500"', $output );
// Should contain embed URL
$this->assertStringContainsString( 'embeddedfolderview', $output );
}
/**
* Test Google Drive URL conversion
*/
public function test_drive_url_conversion() {
$reflection = new ReflectionClass( $this->display_handler );
$method = $reflection->getMethod( 'convert_drive_url_to_embed' );
$method->setAccessible( true );
// Test folder URL conversion
$sharing_url = 'https://drive.google.com/drive/folders/1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs?usp=drive_link';
$embed_url = $method->invoke( $this->display_handler, $sharing_url );
$this->assertEquals( 'https://drive.google.com/embeddedfolderview?id=1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs#list', $embed_url );
// Test invalid URL returns original
$invalid_url = 'https://example.com/not-a-drive-url';
$result = $method->invoke( $this->display_handler, $invalid_url );
$this->assertEquals( $invalid_url, $result );
}
/**
* Test get_announcement_content with permissions
*/
public function test_get_announcement_content_permissions() {
// Test as regular trainer viewing published announcement
wp_set_current_user( $this->regular_trainer );
$content = HVAC_Announcements_Display::get_announcement_content( $this->test_announcements['published'] );
$this->assertStringContainsString( 'Published Announcement', $content );
$this->assertStringContainsString( 'This is published content.', $content );
// Test as regular trainer viewing draft announcement (should be empty)
$content = HVAC_Announcements_Display::get_announcement_content( $this->test_announcements['draft'] );
$this->assertEmpty( $content );
// Test as master trainer viewing draft announcement
wp_set_current_user( $this->master_trainer );
$content = HVAC_Announcements_Display::get_announcement_content( $this->test_announcements['draft'] );
$this->assertStringContainsString( 'Draft Announcement', $content );
}
/**
* Test output escaping in get_announcement_content
*/
public function test_output_escaping() {
// Create announcement with special characters
$test_id = wp_insert_post( array(
'post_type' => HVAC_Announcements_CPT::get_post_type(),
'post_title' => 'Test & Title with <special> characters',
'post_content' => 'Content with & and < > characters',
'post_status' => 'publish',
'post_author' => $this->master_trainer,
) );
wp_set_current_user( $this->regular_trainer );
$content = HVAC_Announcements_Display::get_announcement_content( $test_id );
// Title should be escaped
$this->assertStringContainsString( 'Test &amp; Title with &lt;special&gt; characters', $content );
// Clean up
wp_delete_post( $test_id, true );
}
/**
* Test categories and tags display
*/
public function test_categories_and_tags_display() {
// Add category and tags to announcement
$category_id = wp_insert_term( 'Test Category', HVAC_Announcements_CPT::get_category_taxonomy() );
wp_set_post_terms(
$this->test_announcements['published'],
array( $category_id['term_id'] ),
HVAC_Announcements_CPT::get_category_taxonomy()
);
wp_set_post_terms(
$this->test_announcements['published'],
array( 'tag1', 'tag2' ),
HVAC_Announcements_CPT::get_tag_taxonomy()
);
wp_set_current_user( $this->regular_trainer );
$content = HVAC_Announcements_Display::get_announcement_content( $this->test_announcements['published'] );
// Should contain categories and tags
$this->assertStringContainsString( 'Categories:', $content );
$this->assertStringContainsString( 'Test Category', $content );
$this->assertStringContainsString( 'Tags:', $content );
$this->assertStringContainsString( 'tag1', $content );
$this->assertStringContainsString( 'tag2', $content );
// Clean up
wp_delete_term( $category_id['term_id'], HVAC_Announcements_CPT::get_category_taxonomy() );
}
/**
* Test singleton pattern
*/
public function test_singleton_pattern() {
$instance1 = HVAC_Announcements_Display::get_instance();
$instance2 = HVAC_Announcements_Display::get_instance();
$this->assertSame( $instance1, $instance2 );
}
}