new IcsGeneratorService($appName); // THEN expect($action)->toThrow(\InvalidArgumentException::class, 'App name must be provided for ICS generation.'); }); it('generates ics format without url', function (): void { // GIVEN $service = new IcsGeneratorService('MyApp'); $dto = new IcsContentDto( uid: 'uid-123', summary: 'My Event, with comma', description: "Line 1\nLine 2;", startsAt: Carbon::parse('2026-06-11 10:00:00'), endsAt: Carbon::parse('2026-06-11 11:00:00'), url: null, ); Carbon::setTestNow('2026-06-11 09:00:00'); // WHEN $ics = $service->generate($dto); // THEN expect($ics) ->toContain('BEGIN:VCALENDAR') ->toContain('PRODID:-//MyApp//NONSGML v1.0//EN') ->toContain('UID:uid-123') ->toContain('DTSTAMP:20260611T090000Z') ->toContain('DTSTART:20260611T100000Z') ->toContain('DTEND:20260611T110000Z') ->toContain('SUMMARY:My Event\, with comma') ->toContain('DESCRIPTION:Line 1\nLine 2\;') ->not->toContain('URL:'); Carbon::setTestNow(); }); it('generates ics format with url', function (): void { // GIVEN $service = new IcsGeneratorService('MyApp'); $dto = new IcsContentDto( uid: 'uid-123', summary: 'Event', description: 'Desc', startsAt: Carbon::parse('2026-06-11 10:00:00'), endsAt: Carbon::parse('2026-06-11 11:00:00'), url: 'http://example.com', ); // WHEN $ics = $service->generate($dto); // THEN expect($ics)->toContain('URL:http://example.com'); }); });