PromptVault/tests/Feature/Prompts/PromptActionsTest.php
2026-10-26 15:12:16 -05:00

157 lines
5.5 KiB
PHP

<?php
namespace Tests\Feature\Prompts;
use App\Models\Prompt;
use App\Models\Tag;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PromptActionsTest extends TestCase
{
use RefreshDatabase;
public function test_duplicate_creates_independent_copy_with_reset_stats(): void
{
$alpha = Tag::query()->create(['name' => 'alpha']);
$beta = Tag::query()->create(['name' => 'beta']);
$prompt = Prompt::factory()->create([
'name' => 'Original',
'description' => 'Original description',
'body' => 'Template {{value}}',
'is_favorite' => true,
'usage_count' => 5,
'last_used_at' => '2026-01-01 00:00:00',
]);
$prompt->tags()->attach([$alpha->id, $beta->id]);
$response = $this->post("/prompts/{$prompt->id}/duplicate");
$copy = Prompt::query()->where('id', '!=', $prompt->id)->first();
$this->assertNotNull($copy);
$response->assertRedirect(route('prompts.show', $copy));
$this->assertSame('Original (copy)', $copy->name);
$this->assertSame('Original description', $copy->description);
$this->assertSame('Template {{value}}', $copy->body);
$this->assertFalse($copy->is_favorite);
$this->assertSame(0, $copy->usage_count);
$this->assertNull($copy->last_used_at);
$this->assertSame(['alpha', 'beta'], $copy->tags->pluck('name')->all());
// The original is untouched.
$original = $prompt->fresh();
$this->assertSame('Original', $original->name);
$this->assertTrue($original->is_favorite);
$this->assertSame(5, $original->usage_count);
}
public function test_duplicate_works_without_tags(): void
{
$prompt = Prompt::factory()->create(['name' => 'Bare']);
$response = $this->post("/prompts/{$prompt->id}/duplicate");
$copy = Prompt::query()->where('name', 'Bare (copy)')->first();
$this->assertNotNull($copy);
$response->assertRedirect(route('prompts.show', $copy));
$this->assertCount(0, $copy->tags);
}
public function test_duplicate_appends_copy_until_name_is_unique(): void
{
$original = Prompt::factory()->create(['name' => 'X']);
Prompt::factory()->create(['name' => 'X (copy)']);
$response = $this->post("/prompts/{$original->id}/duplicate");
$copy = Prompt::query()->where('name', 'X (copy) (copy)')->first();
$this->assertNotNull($copy);
$response->assertRedirect(route('prompts.show', $copy));
}
public function test_toggle_favorite_flips_state(): void
{
$prompt = Prompt::factory()->create(['is_favorite' => false]);
$this->post("/prompts/{$prompt->id}/toggle-favorite")->assertRedirect();
$this->assertTrue($prompt->fresh()->is_favorite);
$this->post("/prompts/{$prompt->id}/toggle-favorite")->assertRedirect();
$this->assertFalse($prompt->fresh()->is_favorite);
}
public function test_use_renders_prompt_and_records_usage(): void
{
$prompt = Prompt::factory()->body('Hi {{name}}, welcome to {{place}}.')->create();
$response = $this->postJson("/prompts/{$prompt->id}/use", [
'values' => ['name' => 'Ada', 'place' => 'Lisbon'],
]);
$response->assertOk()->assertJson(['rendered' => 'Hi Ada, welcome to Lisbon.']);
$fresh = $prompt->fresh();
$this->assertSame(1, $fresh->usage_count);
$this->assertNotNull($fresh->last_used_at);
$this->postJson("/prompts/{$prompt->id}/use", [
'values' => ['name' => 'Grace', 'place' => 'Lagos'],
])->assertOk()->assertJson(['rendered' => 'Hi Grace, welcome to Lagos.']);
$this->assertSame(2, $prompt->fresh()->usage_count);
}
public function test_use_reports_missing_variables_without_recording_usage(): void
{
$prompt = Prompt::factory()->body('Hi {{name}} from {{place}}.')->create();
$response = $this->postJson("/prompts/{$prompt->id}/use", [
'values' => ['name' => 'Ada'],
]);
$response->assertStatus(422)->assertJson([
'message' => 'Missing variables: place',
'missing' => ['place'],
]);
$fresh = $prompt->fresh();
$this->assertSame(0, $fresh->usage_count);
$this->assertNull($fresh->last_used_at);
}
public function test_use_reports_all_missing_variables_in_template_order(): void
{
$prompt = Prompt::factory()->body('{{zeta}} then {{alpha}}')->create();
$this->postJson("/prompts/{$prompt->id}/use", ['values' => ['ignored' => 'x']])
->assertStatus(422)
->assertJson([
'message' => 'Missing variables: zeta, alpha',
'missing' => ['zeta', 'alpha'],
]);
}
public function test_use_requires_string_values(): void
{
$prompt = Prompt::factory()->body('Hi {{name}}.')->create();
$this->postJson("/prompts/{$prompt->id}/use", ['values' => ['name' => 42]])
->assertStatus(422);
$this->postJson("/prompts/{$prompt->id}/use", [])
->assertStatus(422);
$this->postJson("/prompts/{$prompt->id}/use", ['values' => 'nope'])
->assertStatus(422);
$this->assertSame(0, $prompt->fresh()->usage_count);
}
public function test_use_404s_for_missing_prompt(): void
{
$this->postJson('/prompts/99999/use', ['values' => ['a' => 'b']])->assertNotFound();
}
}