action = new CreateUserAction(); // Create a planner for testing $this->planner = Planner::factory()->create(); } public function test_it_can_create_a_user_successfully(): void { // Arrange $userData = [ 'name' => 'Test User', 'planner_id' => $this->planner->id, ]; // Act $user = $this->action->execute($userData); // Assert $this->assertInstanceOf(User::class, $user); $this->assertEquals('Test User', $user->name); $this->assertEquals($this->planner->id, $user->planner_id); $this->assertDatabaseHas('users', [ 'id' => $user->id, 'name' => 'Test User', 'planner_id' => $this->planner->id, ]); } public function test_it_throws_exception_when_name_is_empty(): void { // Arrange $userData = [ 'name' => '', 'planner_id' => $this->planner->id, ]; // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Name is required'); $this->action->execute($userData); // Verify no user was created $this->assertDatabaseMissing('users', [ 'planner_id' => $this->planner->id, ]); } public function test_it_throws_exception_when_name_is_missing(): void { // Arrange $userData = [ 'planner_id' => $this->planner->id, ]; // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Name is required'); $this->action->execute($userData); } public function test_it_throws_exception_when_planner_id_is_empty(): void { // Arrange $userData = [ 'name' => 'Test User', 'planner_id' => '', ]; // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Planner ID is required'); $this->action->execute($userData); } public function test_it_throws_exception_when_planner_id_is_missing(): void { // Arrange $userData = [ 'name' => 'Test User', ]; // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Planner ID is required'); $this->action->execute($userData); } public function test_it_logs_creation_process(): void { // Arrange Log::spy(); $userData = [ 'name' => 'Test User', 'planner_id' => $this->planner->id, ]; // Act $user = $this->action->execute($userData); // Assert Log::shouldHaveReceived('info') ->with('CreateUserAction: Starting user creation', [ 'name' => 'Test User', 'planner_id' => $this->planner->id, ]); Log::shouldHaveReceived('info') ->with('CreateUserAction: User successfully created', [ 'user_id' => $user->id, 'name' => 'Test User', 'planner_id' => $this->planner->id, ]); } public function test_it_handles_database_transaction_rollback_on_failure(): void { // Arrange $userData = [ 'name' => 'Test User', 'planner_id' => 999999, // Non-existent planner ID should cause foreign key constraint error ]; // Act & Assert $this->expectException(\Exception::class); try { $this->action->execute($userData); } catch (\Exception $e) { // Verify no user was created (transaction rolled back) $this->assertDatabaseMissing('users', [ 'name' => 'Test User', ]); throw $e; } } public function test_it_logs_errors_on_failure(): void { // Arrange Log::spy(); $userData = [ 'name' => 'Test User', 'planner_id' => 999999, // Non-existent planner ID ]; // Act & Assert try { $this->action->execute($userData); } catch (\Exception $e) { // Expected } // Assert Log::shouldHaveReceived('error') ->with('CreateUserAction: User creation failed', \Mockery::on(function ($data) { return $data['name'] === 'Test User' && $data['planner_id'] === 999999 && isset($data['error']) && isset($data['trace']); })); } public function test_it_creates_user_with_whitespace_trimmed_name(): void { // Arrange $userData = [ 'name' => ' Test User ', 'planner_id' => $this->planner->id, ]; // Act $user = $this->action->execute($userData); // Assert $this->assertEquals(' Test User ', $user->name); // Should preserve original data as passed $this->assertDatabaseHas('users', [ 'id' => $user->id, 'name' => ' Test User ', 'planner_id' => $this->planner->id, ]); } public function test_it_can_create_multiple_users_with_same_planner(): void { // Arrange $userData1 = [ 'name' => 'User One', 'planner_id' => $this->planner->id, ]; $userData2 = [ 'name' => 'User Two', 'planner_id' => $this->planner->id, ]; // Act $user1 = $this->action->execute($userData1); $user2 = $this->action->execute($userData2); // Assert $this->assertNotEquals($user1->id, $user2->id); $this->assertEquals($this->planner->id, $user1->planner_id); $this->assertEquals($this->planner->id, $user2->planner_id); $this->assertDatabaseHas('users', ['name' => 'User One']); $this->assertDatabaseHas('users', ['name' => 'User Two']); } protected function tearDown(): void { \Mockery::close(); parent::tearDown(); } }