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('theo@example.com', $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 = 'theo@example.com'): 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) ; } }