Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Prompt Deck Laravel Package

veeqtoh/prompt-deck

View on GitHub
Deep Wiki
Context7

title: "Testing"php description: "Testing strategies and examples for prompts, commands, tracking, and AI SDK integration."

Introduction

Deck by PromptPHP is designed to be easily testable. This guide covers strategies for testing prompts, commands, tracking, and AI SDK integration in your Laravel application.

Setting up tests

Test base class

If you're using Orchestra Testbench (recommended for package testing), register the service provider in your test case:

<?php

namespace Tests;

use Orchestra\Testbench\TestCase as BaseTestCase;
use PromptPHP\Deck\Providers\DeckServiceProvider;

abstract class TestCase extends BaseTestCase
{
    protected function getPackageProviders($app): array
    {
        return [
            DeckServiceProvider::class,
        ];
    }

    protected function getPackageAliases($app): array
    {
        return [
            'Deck' => \PromptPHP\Deck\Facades\Deck::class,
        ];
    }
}

Disabling cache and tracking

For most tests, disable caching and tracking to avoid side effects:

protected function defineEnvironment($app): void
{
    $app['config']->set('deck.cache.enabled', false);
    $app['config']->set('deck.tracking.enabled', false);
    $app['config']->set('deck.path', $this->getFixturePath('prompts'));
}

protected function getFixturePath(string $path = ''): string
{
    return __DIR__ . '/fixtures/' . $path;
}

Testing prompts

Creating test prompt files

Create fixture prompt files in your test directory:

tests/
└── fixtures/
    └── prompts/
        └── order-summary/
            ├── v1/
            │   ├── system.md
            │   ├── user.md
            │   └── metadata.json
            └── metadata.json

tests/fixtures/prompts/order-summary/v1/system.md:

You are a {{ $tone }} AI assistant specialized in order summaries.

tests/fixtures/prompts/order-summary/v1/user.md:

Summarise this order: {{ $input }}

Testing prompt loading

use PromptPHP\Deck\Facades\Deck;

it('loads a prompt by name', function () {
    $prompt = Deck::get('order-summary', 1);

    expect($prompt->name())->toBe('order-summary');
    expect($prompt->version())->toBe(1);
});

it('throws when prompt does not exist', function () {
    Deck::get('non-existent');
})->throws(\PromptPHP\Deck\Exceptions\PromptNotFoundException::class);

it('throws when version does not exist', function () {
    Deck::get('order-summary', 999);
})->throws(\PromptPHP\Deck\Exceptions\InvalidVersionException::class);

Testing variable interpolation

it('interpolates variables in prompt content', function () {
    $prompt = Deck::get('order-summary', 1);

    $content = $prompt->system(['tone' => 'friendly']);

    expect($content)->toContain('friendly');
    expect($content)->not->toContain('{{ $tone }}');
});

it('leaves unmatched placeholders intact', function () {
    $prompt = Deck::get('order-summary', 1);

    $content = $prompt->system([]);

    expect($content)->toContain('{{ $tone }}');
});

Testing roles

it('lists available roles', function () {
    $prompt = Deck::get('order-summary', 1);

    expect($prompt->roles())->toContain('system', 'user');
});

it('checks if a role exists', function () {
    $prompt = Deck::get('order-summary', 1);

    expect($prompt->has('system'))->toBeTrue();
    expect($prompt->has('nonexistent'))->toBeFalse();
});

it('returns empty string for missing roles', function () {
    $prompt = Deck::get('order-summary', 1);

    expect($prompt->role('nonexistent'))->toBe('');
});

it('gets raw content without interpolation', function () {
    $prompt = Deck::get('order-summary', 1);

    $raw = $prompt->raw('system');

    expect($raw)->toContain('{{ $tone }}');
});

Testing messages output

it('builds messages array for AI APIs', function () {
    $prompt = Deck::get('order-summary', 1);

    $messages = $prompt->toMessages(['tone' => 'friendly', 'input' => 'Order #123']);

    expect($messages)->toBeArray();
    expect($messages[0])->toHaveKeys(['role', 'content']);
    expect($messages[0]['role'])->toBe('system');
});

it('filters messages to specific roles', function () {
    $prompt = Deck::get('order-summary', 1);

    $messages = $prompt->toMessages([], ['system']);

    expect($messages)->toHaveCount(1);
    expect($messages[0]['role'])->toBe('system');
});

Testing with the facade

You can mock the facade in tests where you don't want filesystem access:

use PromptPHP\Deck\Facades\Deck;
use PromptPHP\Deck\PromptTemplate;

it('uses a mocked prompt', function () {
    Deck::shouldReceive('get')
        ->with('order-summary', null)
        ->andReturn(new PromptTemplate(
            'order-summary',
            1,
            ['system' => 'You are a helpful assistant.'],
            ['description' => 'Test prompt']
        ));

    $prompt = Deck::get('order-summary');

    expect($prompt->system())->toBe('You are a helpful assistant.');
});

Testing version management

it('lists all versions for a prompt', function () {
    $versions = Deck::versions('order-summary');

    expect($versions)->toBeArray();
    expect($versions[0])->toHaveKey('version');
});

it('activates a specific version', function () {
    // With tracking disabled, this writes to metadata.json
    $result = Deck::activate('order-summary', 1);

    expect($result)->toBeTrue();
});

Testing execution tracking

When testing tracking, enable it and run the migrations in your test setup:

protected function defineEnvironment($app): void
{
    $app['config']->set('deck.tracking.enabled', true);
    $app['config']->set('database.default', 'testing');
}

protected function defineDatabaseMigrations(): void
{
    $this->loadMigrationsFrom(__DIR__ . '/../src/database/migrations');
}
use PromptPHP\Deck\Models\PromptExecution;

it('tracks prompt executions', function () {
    Deck::track('order-summary', 1, [
        'input'  => ['message' => 'test'],
        'output' => 'response',
        'tokens' => 100,
    ]);

    expect(PromptExecution::count())->toBe(1);
    expect(PromptExecution::first()->prompt_name)->toBe('order-summary');
    expect(PromptExecution::first()->tokens)->toBe(100);
});

it('does not track when disabled', function () {
    config(['deck.tracking.enabled' => false]);

    Deck::track('order-summary', 1, ['tokens' => 50]);

    expect(PromptExecution::count())->toBe(0);
});

Using factories

Use the included factories to seed test data:

use PromptPHP\Deck\Models\PromptVersion;
use PromptPHP\Deck\Models\PromptExecution;

it('queries execution data', function () {
    PromptExecution::factory()
        ->forPrompt('order-summary', 2)
        ->count(10)
        ->create();

    $avg = PromptExecution::where('prompt_name', 'order-summary')
        ->avg('latency_ms');

    expect($avg)->toBeGreaterThan(0);
});

it('finds the active version', function () {
    PromptVersion::factory()->named('order-summary')->version(1)->create();
    PromptVersion::factory()->named('order-summary')->version(2)->active()->create();

    $active = PromptVersion::where('name', 'order-summary')
        ->where('is_active', true)
        ->first();

    expect($active->version)->toBe(2);
});

Testing Artisan commands

use Illuminate\Support\Facades\File;

it('creates a prompt via make:prompt', function () {
    $this->artisan('make:prompt', ['name' => 'test-prompt'])
        ->assertSuccessful();

    $promptPath = config('deck.path') . '/test-prompt/v1';
    expect(File::isDirectory($promptPath))->toBeTrue();
    expect(File::exists($promptPath . '/system.md'))->toBeTrue();
});

it('lists prompts via prompt:list', function () {
    // Create a prompt first
    $this->artisan('make:prompt', ['name' => 'list-test']);

    $this->artisan('prompt:list')
        ->assertSuccessful();
});

it('activates a version via prompt:activate', function () {
    $this->artisan('make:prompt', ['name' => 'activate-test']);

    $this->artisan('prompt:activate', [
        'name'    => 'activate-test',
        'version' => 1,
    ])->assertSuccessful();
});

it('tests a prompt via prompt:test', function () {
    $this->artisan('make:prompt', ['name' => 'render-test']);

    $this->artisan('prompt:test', [
        'name' => 'render-test',
    ])->assertSuccessful();
});

it('shows diff between versions', function () {
    $this->artisan('make:prompt', ['name' => 'diff-test']);

    $this->artisan('prompt:diff', [
        'name'  => 'diff-test',
        '--v1'  => 1,
        '--v2'  => 1,  // Compare with self for basic test
    ])->assertSuccessful();
});

Testing AI SDK integration

Testing HasPromptTemplate

Create a test agent class that uses the trait:

use PromptPHP\Deck\Concerns\HasPromptTemplate;

class TestAgent
{
    use HasPromptTemplate;
}
it('derives prompt name from class name', function () {
    $agent = new TestAgent;

    expect($agent->promptName())->toBe('test-agent');
});

it('returns null for default prompt version', function () {
    $agent = new TestAgent;

    expect($agent->promptVersion())->toBeNull();
});

it('returns empty array for default variables', function () {
    $agent = new TestAgent;

    expect($agent->promptVariables())->toBe([]);
});

Clearing cached templates

When testing with different prompt versions:

it('clears cached template between tests', function () {
    $agent = new TestAgent;

    // Load v1
    $template1 = $agent->promptTemplate();

    // Clear cache and load fresh
    $agent->forgetPromptTemplate();
    $template2 = $agent->promptTemplate();

    // Both are fresh instances
    expect($template1)->not->toBe($template2);
});
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ilhamsyabani/laravel-volt-starter
thethunderturner/filament-latex
ghostcompiler/laravel-querybuilder
webrek/laravel-telescope-mongodb
anousss007/blatui
zatona-eg/zatona-eg-api
cocosmos/filament-sticky-save-bar
patrickbussmann/oauth2-apple
3brs/enterprise-security-bundle
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat