Files
InvoiceShelf/tests/Unit/PromptLoaderTest.php
Darko Gjorgjijoski 5b53a7c283 refactor(ai): move chat + text-gen prompts into resources/ai/prompts/
Extracts the two inline LLM prompts (AiAssistantService's chat system
prompt and AiTextGenerationService's writing preamble) out of PHP
heredocs and into plain-markdown template files under resources/ai/
prompts/. Each file can now be edited without opening a service
class, without wrestling with PHP string interpolation, and with
proper markdown syntax highlighting in editors.

A tiny PromptLoader helper at app/Support/Ai/PromptLoader.php reads
the file and does {{placeholder}} substitution via strtr() — no
Blade, because Blade's {{ $var }} HTML-escapes ampersands and quotes,
which is wrong for LLM prompts (a company called "Smith & Co" would
be sent as "Smith & Co"). Missing templates throw RuntimeException
so they fail loud during development.

Pure refactor: no prompt wording changes. Existing AI feature tests
(AiChatFlowTest, AiGenerationTest) pass unchanged — they assert on
message structure via ScriptedAiDriver, not on prompt content. Three
new unit tests in PromptLoaderTest lock the helper's contract:
placeholder substitution, no-var loading, missing-file error.
2026-04-11 21:08:43 +02:00

37 lines
1.3 KiB
PHP

<?php
use App\Support\Ai\PromptLoader;
test('load substitutes placeholders in the chat-system template', function () {
$prompt = PromptLoader::load('chat-system', [
'user_name' => 'Jane Doe',
'company_name' => 'Acme Corp',
'today' => '2026-04-11',
]);
// Substituted values present
expect($prompt)->toContain('Jane Doe');
expect($prompt)->toContain('Acme Corp');
expect($prompt)->toContain('2026-04-11');
// Raw placeholders are gone
expect($prompt)->not->toContain('{{user_name}}');
expect($prompt)->not->toContain('{{company_name}}');
expect($prompt)->not->toContain('{{today}}');
});
test('load returns a trimmed template when no placeholders are provided', function () {
$prompt = PromptLoader::load('text-generation');
expect($prompt)->not->toBe('');
// No leading/trailing whitespace — trim() stripped the trailing newline.
expect($prompt)->toBe(trim($prompt));
// Sanity-check a word known to appear in the preamble.
expect($prompt)->toContain('writing assistant');
});
test('load throws when the template file is missing', function () {
expect(fn () => PromptLoader::load('definitely-not-a-real-prompt'))
->toThrow(RuntimeException::class, 'Missing AI prompt template: definitely-not-a-real-prompt');
});