PHP code example of kevinpijning / pest-plugin-prompt
1. Go to this page and download the library: Download kevinpijning/pest-plugin-prompt library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
kevinpijning / pest-plugin-prompt example snippets
test('greeting prompt works correctly', function () {
prompt('You are a helpful assistant. Greet {{name}} warmly.')
->usingProvider('openai:gpt-4o-mini')
->expect(['name' => 'Alice'])
->toContain('Alice');
});
// Single prompt
prompt('You are a helpful assistant.');
// Multiple prompts (tested against each other)
prompt(
'You are a helpful assistant.',
'You are a professional assistant.'
);
// With variables
prompt('Greet {{name}} warmly.');
// Register a simple provider
provider('openai-gpt4')->id('openai:gpt-4');
// Register with full configuration
provider('custom-openai')
->id('openai:gpt-4')
->label('Custom OpenAI')
->temperature(0.7)
->maxTokens(2000);
// Use in tests
prompt('Hello')
->usingProvider('custom-openai')
->expect()
->toContain('Hi');
// Fluent group definition
assertion('be nice')
->toBeJudged('friendly')
->toContain('please');
prompt('Explain {{topic}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['topic' => 'AI'])
->to('be nice');
// Callback group with arguments
assertion('be kind', function (TestCase $tc, string $tone): void {
$tc->toBeJudged("response is {$tone} and helpful")
->toContain($tone);
});
prompt('Explain {{topic}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['topic' => 'AI'])
->to('be kind', ['tone' => 'friendly']);
// Magic method equivalent of to('be nice') / to('be kind', ...)
prompt('Explain {{topic}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['topic' => 'AI'])
->toBeNice()
->toBeKind(['tone' => 'friendly']);
prompt('You are a helpful assistant.')
->describe('Tests basic assistant greeting')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('Hello');
// Single provider by ID
prompt('Hello')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('Hi');
// Multiple providers (compares responses)
prompt('What is 2+2?')
->usingProvider('openai:gpt-4o-mini', 'anthropic:claude-3')
->expect()
->toContain('4');
// Provider instance
$provider = provider()
->id('openai:gpt-4')
->temperature(0.7);
prompt('Hello')
->usingProvider($provider)
->expect()
->toContain('Hi');
// Use default provider (openai:gpt-4o-mini)
prompt('Hello')
->expect()
->toContain('Hi');
prompt('Translate {{message}} to {{language}}.')
->usingProvider('openai:gpt-4o-mini')
->alwaysExpect(['message' => 'Hello World!'])
->toBeJudged('the language is always a friendly variant')
->toBeJudged('the source and output language are always mentioned in the response')
->expect(['language' => 'es'])
->toContain('hola')
->toBeJudged('Contains the translation of Hello world! in spanish');
prompt('Translate {{message}} to {{language}}.')
->usingProvider('openai:gpt-4o-mini')
->alwaysExpect(
['message' => 'Hello World!'],
function (TestCase $testCase) {
$testCase
->toBeJudged('the language is always a friendly variant')
->toBeJudged('the source and output language are always mentioned in the response');
}
)
->expect(['language' => 'es'])
->toContain('hola');
prompt('Explain {{topic}} in detail.')
->usingProvider('openai:gpt-4o-mini')
->expect(['topic' => 'quantum computing'])
->to(function (TestCase $testCase) {
$testCase
->toContain('quantum')
->toContain('computing')
->toBeJudged('explanation is clear and accurate')
->toHaveLatency(2000);
});
// Using group() (same as to())
prompt('Analyze {{data}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['data' => 'sales figures'])
->group(function (TestCase $testCase) {
$testCase
->toContain('analysis')
->toBeJudged('analysis is thorough');
});
// Chaining multiple groups
prompt('Review {{document}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['document' => 'contract'])
->to(fn (TestCase $tc) => $tc->toContain('terms'))
->group(fn (TestCase $tc) => $tc->toBeJudged('review is comprehensive'))
->to(fn (TestCase $tc) => $tc->toHaveLatency(1500));
// Define an invokable class
class QualityAssertions
{
public function __invoke(TestCase $testCase): void
{
$testCase
->toBeJudged('response is professional and accurate')
->toHaveLatency(2000)
->not->toBeRefused();
}
}
// Use the class by FQN
prompt('Explain {{topic}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['topic' => 'AI'])
->to(QualityAssertions::class);
// Or use an instance
prompt('Explain {{topic}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['topic' => 'AI'])
->to(new QualityAssertions);
// Works with group() too
prompt('Analyze {{data}}.')
->usingProvider('openai:gpt-4o-mini')
->expect(['data' => 'metrics'])
->group(QualityAssertions::class);
prompt('What is the capital of France?')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('Paris');
// Case-sensitive matching
prompt('What is the capital of France?')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('Paris', strict: true);
// With threshold (similarity score, 0.0 to 1.0)
prompt('Explain quantum computing.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('quantum', threshold: 0.8);
// With custom options
prompt('What is AI?')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('artificial intelligence', options: ['normalize': true]);
prompt('Describe a healthy meal.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainAll(['protein', 'vegetables', 'grains']);
// Case-sensitive
prompt('Describe a healthy meal.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainAll(['Protein', 'Vegetables'], strict: true);
// With threshold
prompt('Describe a healthy meal.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainAll(['protein', 'vegetables'], threshold: 0.9);
prompt('What is the weather like?')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainAny(['sunny', 'rainy', 'cloudy']);
// Case-sensitive
prompt('What is the weather like?')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainAny(['Sunny', 'Rainy'], strict: true);
prompt('Return user data as JSON: name, age, email')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainJson();
prompt('Generate an HTML list of fruits')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainHtml();
prompt('Write a SQL query to select all users')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainSql();
prompt('Generate XML for a product catalog')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainXml();
prompt('Calculate 335 + 85. Return only the number.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toEqual(420);
prompt('Calculate 335 + 85. Return only the number.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBe(420);
prompt('Explain quantum computing to a beginner.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeJudged('The explanation should be clear, accurate, and use simple language.');
// With threshold (minimum score 0.0 to 1.0)
prompt('Write a product description.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeJudged('The description should be persuasive and highlight key features.', threshold: 0.8);
// With custom options
prompt('Write a product description.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeJudged('Should be professional and engaging.', options: ['provider': 'openai:gpt-4']);
prompt('Generate a greeting.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->startsWith('Hello');
// Case-sensitive
prompt('Generate a greeting.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->startsWith('Hello', strict: true);
// With threshold
prompt('Generate a greeting.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->startsWith('Hello', threshold: 0.9);
prompt('Generate a phone number.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toMatchRegex('/\d{3}-\d{3}-\d{4}/');
// With threshold
prompt('Generate a phone number.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toMatchRegex('/\d{3}-\d{3}-\d{4}/', threshold: 0.9);
prompt('Return user data as JSON: name, age, email')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeJson();
// With JSON schema validation
prompt('Return user data as JSON.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeJson([
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
'age' => ['type' => 'number'],
],
'
prompt('Extract the person info from: {{text}}')
->usingProvider('openai:gpt-4o-mini')
->expect(['text' => 'John is 30 years old'])
->toEqualJson([
'name' => 'John',
'age' => 30,
]);
// Works with nested structures
prompt('Extract address info.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toEqualJson([
'user' => [
'name' => 'John',
'address' => [
'city' => 'Amsterdam',
],
],
]);
// Simple key validation
prompt('Return user data as JSON.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toMatchJsonStructure(['name', 'age', 'email']);
// Nested structure validation
prompt('Return user with address.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toMatchJsonStructure([
'name',
'address' => ['street', 'city', 'country'],
]);
// Array items with wildcard (*)
prompt('Return a list of users.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toMatchJsonStructure([
'users' => [
'*' => ['id', 'name', 'email'],
],
]);
prompt('Extract person info from: {{text}}')
->usingProvider('openai:gpt-4o-mini')
->expect(['text' => 'John Doe is 30 years old'])
->toHaveJsonFragment(['name' => 'John Doe'])
->toHaveJsonFragment(['age' => 30]);
// Works with nested values
prompt('Extract user with address.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonFragment([
'address' => ['city' => 'Amsterdam'],
]);
prompt('Extract person info from: {{text}}')
->usingProvider('openai:gpt-4o-mini')
->expect(['text' => 'Jane Smith is 25 years old and lives in Berlin'])
->toHaveJsonFragments([
['name' => 'Jane Smith'],
['age' => 25],
['city' => 'Berlin'],
]);
// Check path exists
prompt('Return user with address.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonPath('name')
->toHaveJsonPath('address.city');
// Check path has specific value
prompt('Extract person info.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonPath('name', 'John Doe')
->toHaveJsonPath('address.city', 'Amsterdam');
// Array index access
prompt('Return list of users.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonPath('users.0.name')
->toHaveJsonPath('users.1.name', 'Jane');
// Wildcard for all array items
prompt('Return list of users.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonPath('users.*.name')
->toHaveJsonPath('users.*.status', 'active');
// Check paths exist (array of strings)
prompt('Return user data.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonPaths(['name', 'email', 'address.city']);
// Check paths with values (associative array)
prompt('Extract person info from: {{text}}')
->usingProvider('openai:gpt-4o-mini')
->expect(['text' => 'Grace Lee is 28 years old and lives in Seoul'])
->toHaveJsonPaths([
'name' => 'Grace Lee',
'age' => 28,
'city' => 'Seoul',
]);
// Mix of existence and value checks with wildcards
prompt('Return users list.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonPaths([
'users.*.name',
'users.*.type' => 'customer',
]);
// Basic type validation
prompt('Return user data.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonType('name', 'string')
->toHaveJsonType('age', 'number')
->toHaveJsonType('active', 'boolean');
// Nested path type validation
prompt('Return user with address.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonType('address', 'object')
->toHaveJsonType('address.city', 'string');
// Array and wildcard type validation
prompt('Return list of users.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveJsonType('users', 'array')
->toHaveJsonType('users.*.name', 'string')
->toHaveJsonType('users.*.age', 'number');
prompt('Generate an HTML list of fruits')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeHtml();
prompt('Write a SQL query to select all users')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeSql();
// With authority list (allowed SQL operations)
prompt('Write a SQL query.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeSql(['SELECT', 'INSERT']);
prompt('Generate XML for a product catalog')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeXml();
prompt('Explain artificial intelligence.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeSimilar('AI is the simulation of human intelligence by machines');
// With threshold (default is 0.75)
prompt('Explain artificial intelligence.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeSimilar('AI explanation', threshold: 0.8);
// With custom embedding provider
prompt('Explain artificial intelligence.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeSimilar('AI explanation', provider: 'huggingface:sentence-similarity:model');
// Multiple expected values
prompt('Explain artificial intelligence.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeSimilar(['AI explanation', 'Machine intelligence', 'Artificial intelligence definition']);
prompt('Spell the word "hello".')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveLevenshtein('hello', threshold: 2.0);
prompt('Call the weather function.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveValidOpenaiFunctionCall();
prompt('Use the available tools.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveValidOpenaiToolsCall();
prompt('Call the weather and time functions.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveToolCallF1(['weather', 'time'], threshold: 0.8);
use KevinPijning\Prompt\Enums\FinishReason;
// Using string
prompt('Generate a response.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReason('stop');
// Using enum
prompt('Generate a response.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReason(FinishReason::Stop);
// Check for tool calls
prompt('Use available tools.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReason(FinishReason::ToolCalls);
// Natural completion
prompt('Generate a response.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReasonStop();
// Token limit reached
prompt('Generate a very long response.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReasonLength();
// Content filter triggered
prompt('Generate harmful content.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReasonContentFilter();
// Tool calls made
prompt('Use available tools.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toHaveFinishReasonToolCalls();
prompt('Write a helpful response.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeScoredByPi('Is the response not apologetic and provides a clear, concise answer?', threshold: 0.8);
prompt('Write harmful content.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeRefused();
// Ensure model does NOT refuse safe requests
prompt('What is 2+2?')
->usingProvider('openai:gpt-4o-mini')
->expect()
->not->toBeRefused();
prompt('Generate a response longer than 10 characters.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toPassJavascript('return output.length > 10;');
prompt('Generate a response longer than 10 characters.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toPassPython('return len(output) > 10');
prompt('Generate a response.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toPassWebhook('https://example.com/validate');
test('assistant greets user correctly', function () {
prompt('You are a helpful assistant. Greet {{name}} warmly.')
->usingProvider('openai:gpt-4o-mini')
->expect(['name' => 'Alice'])
->toContain('Alice');
});
test('prompt variations work', function () {
prompt(
'You are a helpful assistant.',
'You are a professional assistant.',
'You are a friendly assistant.'
)
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContain('assistant');
});
test('providers give consistent answers', function () {
prompt('What is 2+2?')
->usingProvider('openai:gpt-4o-mini', 'anthropic:claude-3')
->expect()
->toContain('4');
});
test('greeting works for different names', function () {
prompt('Greet {{name}} warmly.')
->usingProvider('openai:gpt-4o-mini')
->expect(['name' => 'Alice'])
->toContain('Alice')
->and(['name' => 'Bob'])
->toContain('Bob')
->and(['name' => 'Charlie'])
->toContain('Charlie');
});
test('all translations meet quality standards', function () {
prompt('Translate {{message}} to {{language}} in the style {{style}}.')
->usingProvider('openai:gpt-4o-mini')
->alwaysExpect(['style' => 'friendly'])
->toBeJudged('the translation is always accurate and natural')
->toBeJudged('the response is always in a friendly tone')
->expect(['message' => 'Hello', 'language' => 'es'])
->toContain('hola')
->expect(['message' => 'Goodbye', 'language' => 'fr'])
->toContain('au revoir');
});
test('creative writing with high temperature', function () {
$creativeProvider = provider()
->id('openai:gpt-4')
->temperature(0.9)
->maxTokens(500);
prompt('Write a creative story about {{topic}}.')
->usingProvider($creativeProvider)
->expect(['topic' => 'space exploration'])
->toContain('space');
});
test('response meets multiple criteria', function () {
prompt('Generate a user profile as JSON with name, email, and age.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toContainJson()
->toContainAll(['name', 'email', 'age'])
->toBeJudged('The JSON should be well-structured and include all
test('response quality meets standards', function () {
prompt('Explain machine learning to a beginner.')
->usingProvider('openai:gpt-4o-mini')
->expect()
->toBeJudged('The explanation should be clear, accurate, use simple language, and
// Register global providers
provider('support-gpt4')
->id('openai:gpt-4')
->temperature(0.3);
provider('support-claude')
->id('anthropic:claude-3')
->temperature(0.3);
test('customer service prompt evaluation', function () {
// Test multiple prompts across multiple providers
prompt(
'You are a customer support agent. Help the customer with: {{issue}}',
'As a support agent, assist with: {{issue}}'
)
->describe('Customer service prompt evaluation')
->usingProvider('support-gpt4', 'support-claude')
->expect(['issue' => 'refund request'])
->toContainAll(['refund', 'help'], strict: false)
->toBeJudged('Response should be professional, empathetic, and helpful.', threshold: 0.8)
->and(['issue' => 'product question'])
->toContainAny(['product', 'feature', 'specification'])
->toBeJudged('Response should accurately answer the product question.');
});