feat: create ClickUp task after confirming accommodation booking
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\MessageHandler;
|
||||
|
||||
use App\ClickUp\ApiClient;
|
||||
use App\ClickUp\Exception\ClickUpException;
|
||||
use App\Entity\Groups\Accommodation;
|
||||
use App\Entity\Groups\AccommodationBooking;
|
||||
use App\Message\CreateClickUpBookingTaskMessage;
|
||||
use App\MessageHandler\CreateClickUpBookingTaskHandler;
|
||||
use App\Repository\Groups\AccommodationBookingRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
class CreateClickUpBookingTaskHandlerTest extends TestCase
|
||||
{
|
||||
public function testCreatesTheTaskAndMovesItIntoTheGroupsStatus(): void
|
||||
{
|
||||
$repository = $this->createMock(AccommodationBookingRepository::class);
|
||||
$repository->method('find')->with(42)->willReturn($this->booking());
|
||||
|
||||
$client = $this->createMock(ApiClient::class);
|
||||
$client->method('isConfigured')->willReturn(true);
|
||||
$client->expects(self::once())
|
||||
->method('createTaskFromTemplate')
|
||||
->with('WIEN01 2026-08-20 Anna Müller')
|
||||
->willReturn('abc123');
|
||||
$client->expects(self::once())
|
||||
->method('updateTaskStatus')
|
||||
->with('abc123', CreateClickUpBookingTaskHandler::TASK_STATUS);
|
||||
|
||||
$this->handler($repository, $client)(new CreateClickUpBookingTaskMessage(42));
|
||||
}
|
||||
|
||||
public function testAnUnconfiguredClientIsSkippedWithoutTouchingTheDatabase(): void
|
||||
{
|
||||
$repository = $this->createMock(AccommodationBookingRepository::class);
|
||||
$repository->expects(self::never())->method('find');
|
||||
|
||||
$client = $this->createMock(ApiClient::class);
|
||||
$client->method('isConfigured')->willReturn(false);
|
||||
$client->expects(self::never())->method('createTaskFromTemplate');
|
||||
|
||||
$this->handler($repository, $client)(new CreateClickUpBookingTaskMessage(42));
|
||||
}
|
||||
|
||||
public function testAVanishedBookingIsSkipped(): void
|
||||
{
|
||||
$repository = $this->createMock(AccommodationBookingRepository::class);
|
||||
$repository->method('find')->willReturn(null);
|
||||
|
||||
$client = $this->createMock(ApiClient::class);
|
||||
$client->method('isConfigured')->willReturn(true);
|
||||
$client->expects(self::never())->method('createTaskFromTemplate');
|
||||
|
||||
$this->handler($repository, $client)(new CreateClickUpBookingTaskMessage(42));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider incompleteBookings
|
||||
*/
|
||||
public function testABookingWithoutTheDataForATaskNameIsSkipped(callable $mutate): void
|
||||
{
|
||||
$booking = $this->booking();
|
||||
$mutate($booking);
|
||||
|
||||
$repository = $this->createMock(AccommodationBookingRepository::class);
|
||||
$repository->method('find')->willReturn($booking);
|
||||
|
||||
$client = $this->createMock(ApiClient::class);
|
||||
$client->method('isConfigured')->willReturn(true);
|
||||
$client->expects(self::never())->method('createTaskFromTemplate');
|
||||
|
||||
$this->handler($repository, $client)(new CreateClickUpBookingTaskMessage(42));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iterable<string, array{callable(AccommodationBooking): void}>
|
||||
*/
|
||||
public static function incompleteBookings(): iterable
|
||||
{
|
||||
yield 'without an accommodation' => [static fn (AccommodationBooking $b) => $b->setAccommodation(null)];
|
||||
yield 'without a contact name' => [static function (AccommodationBooking $b): void {
|
||||
$b->setFirstName(null);
|
||||
$b->setLastName(null);
|
||||
}];
|
||||
yield 'with a blank contact name' => [static function (AccommodationBooking $b): void {
|
||||
$b->setFirstName(' ');
|
||||
$b->setLastName(' ');
|
||||
}];
|
||||
}
|
||||
|
||||
public function testAFailingStatusUpdateDoesNotRetryTheTaskCreation(): void
|
||||
{
|
||||
$repository = $this->createMock(AccommodationBookingRepository::class);
|
||||
$repository->method('find')->willReturn($this->booking());
|
||||
|
||||
$client = $this->createMock(ApiClient::class);
|
||||
$client->method('isConfigured')->willReturn(true);
|
||||
$client->method('createTaskFromTemplate')->willReturn('abc123');
|
||||
$client->method('updateTaskStatus')->willThrowException(new ClickUpException('boom'));
|
||||
|
||||
$this->handler($repository, $client)(new CreateClickUpBookingTaskMessage(42));
|
||||
|
||||
// Reaching this point is the assertion: the exception must not bubble up into the
|
||||
// transport, because a retry would create a second ClickUp task.
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
private function handler(
|
||||
AccommodationBookingRepository $repository,
|
||||
ApiClient $client,
|
||||
): CreateClickUpBookingTaskHandler {
|
||||
return new CreateClickUpBookingTaskHandler($repository, $client, new NullLogger());
|
||||
}
|
||||
|
||||
private function booking(): AccommodationBooking
|
||||
{
|
||||
$accommodation = new Accommodation();
|
||||
$accommodation->setCalendarCode('WIEN01');
|
||||
|
||||
$booking = new AccommodationBooking();
|
||||
$booking->setAccommodation($accommodation);
|
||||
$booking->setDateFrom(new \DateTimeImmutable('2026-08-20'));
|
||||
$booking->setFirstName('Anna');
|
||||
$booking->setLastName('Müller');
|
||||
|
||||
return $booking;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user