157 lines
5.5 KiB
PHP
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();
|
|
}
|
|
}
|