engine = new WorkflowEngine; $this->handler = new ThumbnailGenerationHandler(app(AiProviderManager::class), new AssetStorage); }); test('it generates two default-style variants and completes the step', function () { Http::fake(['api.stability.ai/*' => Http::response(['image' => base64_encode('bytes')])]); AiProvider::factory()->create(['provider' => 'stability_ai']); $project = VideoProject::factory()->create(['title' => 'Top 10 Gadgets']); $step = $this->engine->start($project, [['type' => 'thumbnail_generation']]); $this->handler->handle($step, $this->engine); $fresh = $step->fresh(); expect($fresh->status)->toBe('completed'); expect($fresh->output['variant_count'])->toBe(2); expect($fresh->output['asset_ids'])->toHaveCount(2); $assets = Asset::whereIn('id', $fresh->output['asset_ids'])->get(); $assets->each(fn ($a) => expect($a->type)->toBe('image')); expect($assets->pluck('metadata.style')->sort()->values()->all()) ->toBe(['minimalist and clean', 'vibrant and colorful']); Http::assertSentCount(2); Http::assertSent(fn ($request) => str_contains($request->body(), 'Top 10 Gadgets')); }); test('explicit styles in input override the default variants', function () { Http::fake(['api.stability.ai/*' => Http::response(['image' => base64_encode('bytes')])]); AiProvider::factory()->create(['provider' => 'stability_ai']); $project = VideoProject::factory()->create(); $step = $this->engine->start($project, [['type' => 'thumbnail_generation']]); $step->update(['input' => ['styles' => ['noir', 'retro', 'futuristic']]]); $this->handler->handle($step->fresh(), $this->engine); expect($step->fresh()->output['variant_count'])->toBe(3); Http::assertSentCount(3); }); test('it fails the step when no active StabilityAI provider is configured', function () { $project = VideoProject::factory()->create(); $step = $this->engine->start($project, [['type' => 'thumbnail_generation']]); $this->handler->handle($step, $this->engine); expect($step->fresh()) ->status->toBe('failed') ->error->toContain('No active StabilityAI provider'); }); test('it fails the step and reports which variant failed', function () { Http::fake(['api.stability.ai/*' => Http::response(['errors' => ['bad prompt']], 400)]); AiProvider::factory()->create(['provider' => 'stability_ai']); $project = VideoProject::factory()->create(); $step = $this->engine->start($project, [['type' => 'thumbnail_generation']]); $this->handler->handle($step, $this->engine); expect($step->fresh()) ->status->toBe('failed') ->error->toContain('variant 1'); });