128 lines
4.2 KiB
PHP
128 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Service\Cron;
|
|
|
|
use App\Config\EmailTextKey;
|
|
use App\Email\Mailer;
|
|
use App\Entity\Embeddable\Communication;
|
|
use App\Entity\Teamer;
|
|
use App\Entity\TeamerWorkMonth;
|
|
use App\Repository\TeamerWorkMonthRepository;
|
|
use App\Service\Cron\WorkMonthReminderService;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\NullLogger;
|
|
|
|
/**
|
|
* Pins the rules the reminder applies: which day it runs on, how long it waits after an
|
|
* import, and who it can actually reach. The query itself is the repository's business.
|
|
*/
|
|
class WorkMonthReminderServiceTest extends TestCase
|
|
{
|
|
private TeamerWorkMonthRepository&MockObject $repository;
|
|
private Mailer&MockObject $mailer;
|
|
private WorkMonthReminderService $service;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->repository = $this->createMock(TeamerWorkMonthRepository::class);
|
|
$this->mailer = $this->createMock(Mailer::class);
|
|
|
|
$this->service = new WorkMonthReminderService(
|
|
$this->repository,
|
|
$this->mailer,
|
|
new NullLogger(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* app:cron runs daily, so the weekday gate is the only thing stopping a teamer being
|
|
* chased every morning.
|
|
*/
|
|
public function testItOnlyRunsOnMondays(): void
|
|
{
|
|
$this->repository->expects($this->never())->method('findAwaitingDocument');
|
|
$this->mailer->expects($this->never())->method('createAndSendText');
|
|
|
|
$this->assertSame(
|
|
'Work month reminders are only sent on mondays',
|
|
$this->service->sendReminders(new \DateTimeImmutable('2026-03-10')),
|
|
);
|
|
}
|
|
|
|
public function testItLeavesTheTeamerAGracePeriodAfterTheImport(): void
|
|
{
|
|
$this->repository
|
|
->expects($this->once())
|
|
->method('findAwaitingDocument')
|
|
->with($this->callback(
|
|
static fn (\DateTimeImmutable $cutoff) => '2026-03-04' === $cutoff->format('Y-m-d')
|
|
))
|
|
->willReturn([])
|
|
;
|
|
|
|
// 9 March 2026 is a Monday; the import ran on the 10th of the month before.
|
|
$this->service->sendReminders(new \DateTimeImmutable('2026-03-09'));
|
|
}
|
|
|
|
public function testItMailsOneReminderPerOpenMonth(): void
|
|
{
|
|
$this->repository->method('findAwaitingDocument')->willReturn([
|
|
$this->createWorkMonth(2026, 1),
|
|
$this->createWorkMonth(2026, 2),
|
|
]);
|
|
|
|
$sent = [];
|
|
$this->mailer
|
|
->expects($this->exactly(2))
|
|
->method('createAndSendText')
|
|
->willReturnCallback(function (EmailTextKey $key, array $placeholders, array $options) use (&$sent) {
|
|
$sent[] = [$key, $placeholders, $options];
|
|
})
|
|
;
|
|
|
|
$this->assertSame(
|
|
'Sent 2 work month reminders to teamers',
|
|
$this->service->sendReminders(new \DateTimeImmutable('2026-03-09')),
|
|
);
|
|
|
|
$this->assertSame(EmailTextKey::REMINDER_WORK_MONTH_UPLOAD, $sent[0][0]);
|
|
$this->assertSame('Januar 2026', $sent[0][1]['workMonth']);
|
|
$this->assertSame('Februar 2026', $sent[1][1]['workMonth']);
|
|
$this->assertSame('[email protected]', $sent[0][2]['to']);
|
|
}
|
|
|
|
public function testATeamerWithoutAnAddressIsSkippedSilently(): void
|
|
{
|
|
$this->repository->method('findAwaitingDocument')->willReturn([
|
|
$this->createWorkMonth(2026, 1, null),
|
|
$this->createWorkMonth(2026, 2, ' '),
|
|
$this->createWorkMonth(2026, 3),
|
|
]);
|
|
|
|
$this->mailer->expects($this->once())->method('createAndSendText');
|
|
|
|
$this->assertSame(
|
|
'Sent 1 work month reminders to teamers',
|
|
$this->service->sendReminders(new \DateTimeImmutable('2026-03-09')),
|
|
);
|
|
}
|
|
|
|
private function createWorkMonth(int $year, int $month, ?string $email = '[email protected]'): TeamerWorkMonth
|
|
{
|
|
$communication = new Communication();
|
|
$communication->setEmail($email);
|
|
|
|
$teamer = new Teamer();
|
|
$teamer->setFirstName('Theo')->setLastName('Test')->setCommunication($communication);
|
|
|
|
return (new TeamerWorkMonth())
|
|
->setTeamer($teamer)
|
|
->setYear($year)
|
|
->setMonth($month)
|
|
;
|
|
}
|
|
}
|