upskill-event-manager/wordpress-dev/tests/unit/test-event-management.php
bengizmo cdef12ee80 feat(events): Implement fallback logic and UI for Create/Modify Event page
- Refactored fallback submission logic in `class-event-handler.php` to remove `wp_die`/`exit` calls and use redirects for error handling, enabling proper unit testing.
- Implemented meta-data saving (dates, venue, organizer) in the fallback logic using `update_post_meta`.
- Updated unit tests (`test-event-management.php`) to remove `markTestIncomplete` calls related to handler errors and uncommented meta assertions. Unit tests for fallback logic now pass.
- Added Instructions section and Return to Dashboard button to the event form shortcode (`display_event_form_shortcode`).
- Applied basic theme styling classes (`ast-container`, `notice`, `ast-button`) to the event form.
- Updated `docs/implementation_plan.md` to reflect completion of tasks 4.1-4.5 and set focus to Task 5.

Refs: Task 4.1, 4.2, 4.3, 4.4, 4.5
2025-04-01 11:46:24 -03:00

458 lines
No EOL
18 KiB
PHP

<?php
/**
* Unit tests for event creation and modification logic.
*
* @package Hvac_Community_Events
*/
use Yoast\WPTestUtils\WPIntegration;
/**
* Class Event_Management_Test
*
* Tests the core logic for creating and modifying events.
*/
class Event_Management_Test extends WP_UnitTestCase {
// Removed: use WPIntegration\FactoriesApi; - Use built-in factory from WP_UnitTestCase
/**
* Test trainer user ID.
* @var int
*/
protected static $trainer_user_id;
/**
* Set up the test environment before the class runs.
*/
public static function wpSetUpBeforeClass( $factory ) {
// Create a user with the 'hvac_trainer' role for testing permissions
self::$trainer_user_id = $factory->user->create( [
'role' => 'hvac_trainer',
] );
// Ensure The Events Calendar core classes are loaded if needed
// Note: This might require adjustments based on how TEC is loaded in bootstrap.php
if ( ! class_exists( 'Tribe__Events__Main' ) && defined( 'TRIBE_EVENTS_FILE' ) ) {
require_once dirname( TRIBE_EVENTS_FILE ) . '/src/Tribe/Main.php';
}
}
/**
* Set up the test environment before each test method runs.
*/
public function set_up() {
parent::set_up();
// Set the current user to the test trainer for permission-based tests
wp_set_current_user( self::$trainer_user_id );
}
/**
* Tear down the test environment after each test method runs.
*/
public function tear_down() {
// Reset the current user
wp_set_current_user( 0 );
parent::tear_down();
}
// --- Test Cases ---
/**
* Test that event creation fails if required data (e.g., title) is missing.
* @test
*/
public function test_event_creation_requires_valid_data() {
// Assume TEC CE handler doesn't exist or fails for this test path
if ( class_exists( 'Tribe__Events__Community__Main' ) ) {
$this->markTestSkipped('Skipping manual fallback test when TEC CE is active.');
}
// 1. Prepare POST data missing the title
$_POST = [
'action' => 'hvac_save_event',
'event_id' => 0,
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ),
'event_title' => '', // Missing title
'event_description' => 'Description without title.',
// Add other fields like dates if they are validated in the fallback
];
// 2. Instantiate handler and call method (expecting wp_die or error handling)
$handler = HVAC_Event_Handler::get_instance();
ob_start();
@$handler->process_event_submission();
$output = ob_get_clean(); // Capture potential wp_die output
// 3. Assert no event was created
$args = [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_status' => 'any',
'post_content' => 'Description without title.', // Search by content as title is empty
'posts_per_page' => 1,
];
$events = get_posts( $args );
$this->assertCount( 0, $events, 'No event should have been created with missing title.' );
// Optional: Check output for expected error message if wp_die was caught
// $this->assertStringContainsString( 'Event Title is required', $output );
// TODO: Add more scenarios for other invalid data (e.g., invalid dates)
// Clean up
unset( $_POST );
}
/**
* Test successful event creation with valid data using the fallback logic.
* @test
*/
public function test_event_creation_success() {
// Assume TEC CE handler doesn't exist or fails for this test path
if ( class_exists( 'Tribe__Events__Community__Main' ) ) {
$this->markTestSkipped('Skipping manual fallback test when TEC CE is active.');
}
// 1. Create dependencies
$venue_id = $this->factory()->post->create( [
'post_type' => Tribe__Events__Main::VENUE_POST_TYPE,
'post_title' => 'Test Venue',
'post_status' => 'publish',
] );
$organizer_id = $this->factory()->post->create( [
'post_type' => Tribe__Events__Main::ORGANIZER_POST_TYPE,
'post_title' => 'Test Organizer',
'post_status' => 'publish',
] );
// 2. Prepare mock POST data (using common TEC field names)
$start_date = date( 'Y-m-d H:i:s', strtotime( '+1 day' ) );
$end_date = date( 'Y-m-d H:i:s', strtotime( '+1 day +2 hours' ) );
$_POST = [
'action' => 'hvac_save_event',
'event_id' => 0, // Creating new event
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ), // Generate a valid nonce
'event_title' => 'My Test Event',
'event_description' => 'This is the event description.',
// TEC Date fields (adjust names if needed based on actual form)
'EventStartDate' => date( 'Y-m-d', strtotime( $start_date ) ),
'EventStartTime' => date( 'h:i A', strtotime( $start_date ) ),
'EventEndDate' => date( 'Y-m-d', strtotime( $end_date ) ),
'EventEndTime' => date( 'h:i A', strtotime( $end_date ) ),
// TEC Venue/Organizer fields (adjust names if needed)
'venue' => [ 'VenueID' => $venue_id ],
'organizer' => [ 'OrganizerID' => $organizer_id ],
// Add other necessary fields like cost, categories etc. if required by fallback logic
];
// 3. Instantiate handler and call method
$handler = HVAC_Event_Handler::get_instance();
// Use output buffering to catch potential wp_die output if redirection fails
ob_start();
// We expect this to redirect, so catch potential headers already sent errors/output
@$handler->process_event_submission();
ob_end_clean(); // Discard output buffer
// 4. Assertions
$args = [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_status' => 'publish', // Assuming fallback publishes directly
'title' => 'My Test Event',
'author' => self::$trainer_user_id,
'posts_per_page' => 1,
];
$events = get_posts( $args );
$this->assertCount( 1, $events, 'Expected one event to be created.' );
$created_event_id = $events[0]->ID;
// Assert basic post data
$this->assertEquals( 'My Test Event', $events[0]->post_title );
$this->assertEquals( 'This is the event description.', $events[0]->post_content );
$this->assertEquals( self::$trainer_user_id, $events[0]->post_author );
// Assert meta data (requires fallback logic in handler to save these)
$this->assertEquals( $start_date, get_post_meta( $created_event_id, '_EventStartDate', true ) );
$this->assertEquals( $end_date, get_post_meta( $created_event_id, '_EventEndDate', true ) );
$this->assertEquals( $venue_id, get_post_meta( $created_event_id, '_EventVenueID', true ) );
$this->assertEquals( $organizer_id, get_post_meta( $created_event_id, '_EventOrganizerID', true ) );
// $this->markTestIncomplete( 'Meta data assertions depend on fallback save logic implementation.' ); // Removed
// Clean up post variable
unset( $_POST );
}
/**
* Test successful event modification with valid data using the fallback logic.
* @test
*/
public function test_event_modification_success() {
// Assume TEC CE handler doesn't exist or fails for this test path
if ( class_exists( 'Tribe__Events__Community__Main' ) ) {
$this->markTestSkipped('Skipping manual fallback test when TEC CE is active.');
}
// 1. Create initial event, venue, organizer
$initial_venue_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::VENUE_POST_TYPE, 'post_title' => 'Initial Venue', 'post_status' => 'publish' ] );
$initial_organizer_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::ORGANIZER_POST_TYPE, 'post_title' => 'Initial Organizer', 'post_status' => 'publish' ] );
$event_id = $this->factory()->post->create( [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_title' => 'Initial Event Title',
'post_content' => 'Initial description.',
'post_status' => 'publish',
'post_author' => self::$trainer_user_id,
// TODO: Set initial meta if needed for comparison
] );
// Set initial meta (assuming fallback logic would have done this)
// update_post_meta( $event_id, '_EventVenueID', $initial_venue_id );
// update_post_meta( $event_id, '_EventOrganizerID', $initial_organizer_id );
// 2. Prepare mock POST data for modification
$new_start_date = date( 'Y-m-d H:i:s', strtotime( '+2 day' ) );
$new_end_date = date( 'Y-m-d H:i:s', strtotime( '+2 day +3 hours' ) );
$new_venue_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::VENUE_POST_TYPE, 'post_title' => 'New Venue', 'post_status' => 'publish' ] );
$_POST = [
'action' => 'hvac_save_event',
'event_id' => $event_id, // Modifying existing event
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ),
'event_title' => 'Updated Test Event Title',
'event_description' => 'Updated event description.',
// TEC Date fields
'EventStartDate' => date( 'Y-m-d', strtotime( $new_start_date ) ),
'EventStartTime' => date( 'h:i A', strtotime( $new_start_date ) ),
'EventEndDate' => date( 'Y-m-d', strtotime( $new_end_date ) ),
'EventEndTime' => date( 'h:i A', strtotime( $new_end_date ) ),
// TEC Venue/Organizer fields
'venue' => [ 'VenueID' => $new_venue_id ], // Change venue
'organizer' => [ 'OrganizerID' => $initial_organizer_id ], // Keep organizer
// Add other fields as needed
];
// 3. Instantiate handler and call method
$handler = HVAC_Event_Handler::get_instance();
ob_start();
@$handler->process_event_submission();
ob_end_clean();
// 4. Assertions
$updated_event = get_post( $event_id );
$this->assertNotNull( $updated_event, 'Event post should still exist.' );
$this->assertEquals( 'Updated Test Event Title', $updated_event->post_title );
$this->assertEquals( 'Updated event description.', $updated_event->post_content );
$this->assertEquals( self::$trainer_user_id, $updated_event->post_author ); // Author should not change
// Assert meta data (requires fallback logic in handler to save these)
$this->assertEquals( $new_start_date, get_post_meta( $event_id, '_EventStartDate', true ) );
$this->assertEquals( $new_end_date, get_post_meta( $event_id, '_EventEndDate', true ) );
$this->assertEquals( $new_venue_id, get_post_meta( $event_id, '_EventVenueID', true ) );
$this->assertEquals( $initial_organizer_id, get_post_meta( $event_id, '_EventOrganizerID', true ) ); // Ensure organizer didn't change unexpectedly
// $this->markTestIncomplete( 'Meta data assertions depend on fallback save logic implementation.' ); // Removed
// Clean up post variable
unset( $_POST );
}
/**
* Test that a user without the correct role/capabilities cannot create an event.
* @test
*/
public function test_unauthorized_user_cannot_create_event() {
// 1. Set user to subscriber
$subscriber_id = $this->factory()->user->create( [ 'role' => 'subscriber' ] );
wp_set_current_user( $subscriber_id );
// 2. Prepare minimal POST data
$_POST = [
'action' => 'hvac_save_event',
'event_id' => 0,
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ),
'event_title' => 'Unauthorized Event Attempt',
// Other fields not strictly necessary for permission check
];
// 3. Instantiate handler and call method (expecting wp_die)
$handler = HVAC_Event_Handler::get_instance();
ob_start();
// Use @ to suppress expected wp_die output/error
@$handler->process_event_submission();
$output = ob_get_clean(); // Capture output in case we want to check it later
// 4. Assert no event was created
$args = [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_status' => 'any', // Check all statuses
'title' => 'Unauthorized Event Attempt',
'posts_per_page' => 1,
];
$events = get_posts( $args );
$this->assertCount( 0, $events, 'No event should have been created by an unauthorized user.' );
// Optional: Check output for expected error message if wp_die was caught
// $this->assertStringContainsString( 'You do not have permission', $output ); // This might be fragile
// Clean up
unset( $_POST );
wp_set_current_user( self::$trainer_user_id ); // Reset user for subsequent tests
}
/**
* Test that a user cannot modify an event they don't own (even if they have the trainer role).
* @test
*/
public function test_unauthorized_user_cannot_modify_event() {
// 1. Create initial event owned by the main test trainer
$initial_title = 'Event Owned By Trainer 1';
$event_id = $this->factory()->post->create( [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_title' => $initial_title,
'post_status' => 'publish',
'post_author' => self::$trainer_user_id,
] );
// 2. Create a second trainer user
$other_trainer_id = $this->factory()->user->create( [ 'role' => 'hvac_trainer' ] );
wp_set_current_user( $other_trainer_id );
// 3. Prepare POST data attempting modification
$_POST = [
'action' => 'hvac_save_event',
'event_id' => $event_id, // Target the first trainer's event
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ),
'event_title' => 'Attempted Update By Trainer 2',
// Other fields...
];
// 4. Instantiate handler and call method (expecting wp_die)
$handler = HVAC_Event_Handler::get_instance();
ob_start();
@$handler->process_event_submission();
ob_end_clean();
// 5. Assert the event was NOT modified
$event_post = get_post( $event_id );
$this->assertNotNull( $event_post, 'Event post should still exist.' );
$this->assertEquals( $initial_title, $event_post->post_title, 'Event title should not have been changed by another trainer.' );
// Clean up
unset( $_POST );
wp_set_current_user( self::$trainer_user_id ); // Reset user
}
/**
* Test that venue information is correctly associated with the created event (fallback logic).
* @test
*/
public function test_event_venue_association() {
// Assume TEC CE handler doesn't exist or fails for this test path
if ( class_exists( 'Tribe__Events__Community__Main' ) ) {
$this->markTestSkipped('Skipping manual fallback test when TEC CE is active.');
}
// 1. Create dependencies
$venue_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::VENUE_POST_TYPE, 'post_title' => 'Associated Venue', 'post_status' => 'publish' ] );
$organizer_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::ORGANIZER_POST_TYPE, 'post_title' => 'Associated Organizer', 'post_status' => 'publish' ] );
// 2. Prepare mock POST data
$start_date = date( 'Y-m-d H:i:s', strtotime( '+3 day' ) );
$end_date = date( 'Y-m-d H:i:s', strtotime( '+3 day +2 hours' ) );
$_POST = [
'action' => 'hvac_save_event',
'event_id' => 0,
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ),
'event_title' => 'Event With Venue',
'event_description' => 'Testing venue association.',
'EventStartDate' => date( 'Y-m-d', strtotime( $start_date ) ),
'EventStartTime' => date( 'h:i A', strtotime( $start_date ) ),
'EventEndDate' => date( 'Y-m-d', strtotime( $end_date ) ),
'EventEndTime' => date( 'h:i A', strtotime( $end_date ) ),
'venue' => [ 'VenueID' => $venue_id ], // Key field
'organizer' => [ 'OrganizerID' => $organizer_id ],
];
// 3. Instantiate handler and call method
$handler = HVAC_Event_Handler::get_instance();
ob_start();
@$handler->process_event_submission();
ob_end_clean();
// 4. Assertions
$args = [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_status' => 'publish',
'title' => 'Event With Venue',
'posts_per_page' => 1,
];
$events = get_posts( $args );
$this->assertCount( 1, $events, 'Expected event to be created.' );
$created_event_id = $events[0]->ID;
// Assert meta data (requires fallback logic in handler to save these)
$this->assertEquals( $venue_id, get_post_meta( $created_event_id, '_EventVenueID', true ) );
// $this->markTestIncomplete( 'Venue meta assertion depends on fallback save logic implementation.' ); // Removed
// Clean up
unset( $_POST );
}
/**
* Test that organizer information is correctly associated with the created event (fallback logic).
* @test
*/
public function test_event_organizer_association() {
// Assume TEC CE handler doesn't exist or fails for this test path
if ( class_exists( 'Tribe__Events__Community__Main' ) ) {
$this->markTestSkipped('Skipping manual fallback test when TEC CE is active.');
}
// 1. Create dependencies
$venue_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::VENUE_POST_TYPE, 'post_title' => 'Associated Venue 2', 'post_status' => 'publish' ] );
$organizer_id = $this->factory()->post->create( [ 'post_type' => Tribe__Events__Main::ORGANIZER_POST_TYPE, 'post_title' => 'Associated Organizer 2', 'post_status' => 'publish' ] );
// 2. Prepare mock POST data
$start_date = date( 'Y-m-d H:i:s', strtotime( '+4 day' ) );
$end_date = date( 'Y-m-d H:i:s', strtotime( '+4 day +2 hours' ) );
$_POST = [
'action' => 'hvac_save_event',
'event_id' => 0,
'_hvac_event_nonce' => wp_create_nonce( 'hvac_save_event_nonce' ),
'event_title' => 'Event With Organizer',
'event_description' => 'Testing organizer association.',
'EventStartDate' => date( 'Y-m-d', strtotime( $start_date ) ),
'EventStartTime' => date( 'h:i A', strtotime( $start_date ) ),
'EventEndDate' => date( 'Y-m-d', strtotime( $end_date ) ),
'EventEndTime' => date( 'h:i A', strtotime( $end_date ) ),
'venue' => [ 'VenueID' => $venue_id ],
'organizer' => [ 'OrganizerID' => $organizer_id ], // Key field
];
// 3. Instantiate handler and call method
$handler = HVAC_Event_Handler::get_instance();
ob_start();
@$handler->process_event_submission();
ob_end_clean();
// 4. Assertions
$args = [
'post_type' => Tribe__Events__Main::POSTTYPE,
'post_status' => 'publish',
'title' => 'Event With Organizer',
'posts_per_page' => 1,
];
$events = get_posts( $args );
$this->assertCount( 1, $events, 'Expected event to be created.' );
$created_event_id = $events[0]->ID;
// Assert meta data (requires fallback logic in handler to save these)
$this->assertEquals( $organizer_id, get_post_meta( $created_event_id, '_EventOrganizerID', true ) );
// $this->markTestIncomplete( 'Organizer meta assertion depends on fallback save logic implementation.' ); // Removed
// Clean up
unset( $_POST );
}
}