changesApplyFrom(CarbonImmutable::parse('2026-06-27 21:00', 'Europe/Moscow')); expect($msg)->toContain('27 июня'); }); it('формат даты — род. падеж «D MMMM» по МСК', function (): void { expect(ruleMessages()->formatDate(CarbonImmutable::parse('2026-01-01 12:00', 'Europe/Moscow')))->toBe('1 января'); expect(ruleMessages()->formatDate(CarbonImmutable::parse('2026-05-09 00:00', 'Europe/Moscow')))->toBe('9 мая'); expect(ruleMessages()->formatDate(CarbonImmutable::parse('2026-12-31 23:00', 'Europe/Moscow')))->toBe('31 декабря'); }); it('текст смены источника объясняет хвост старого источника', function (): void { $msg = ruleMessages()->sourceChanged(CarbonImmutable::parse('2026-06-27 21:00', 'Europe/Moscow')); expect($msg)->toContain('по старому источнику') ->and($msg)->toContain('27 июня') ->and($msg)->toContain('дальше — по новому'); }); it('текст паузы объясняет grace-хвост как норму', function (): void { $msg = ruleMessages()->projectPaused(CarbonImmutable::parse('2026-06-27 21:00', 'Europe/Moscow')); expect($msg)->toContain('18:00') ->and($msg)->toContain('это нормально'); }); it('текст создания/возобновления — когда пойдут первые лиды', function (): void { $d = CarbonImmutable::parse('2026-06-26 21:00', 'Europe/Moscow'); expect(ruleMessages()->projectCreated($d))->toContain('Первые лиды пойдут с 26 июня'); expect(ruleMessages()->projectResumed($d))->toContain('Лиды пойдут с 26 июня'); }); it('текст баланса склоняет слово «лид» по числу', function (): void { expect(ruleMessages()->balanceRunningOut(21))->toContain('21 лид.'); expect(ruleMessages()->balanceRunningOut(3))->toContain('3 лида'); expect(ruleMessages()->balanceRunningOut(11))->toContain('11 лидов'); expect(ruleMessages()->balanceRunningOut(105))->toContain('105 лидов'); });