Skip to content

Commit

Permalink
(tests): adds some lovely ol' tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ashleyhindle committed Sep 8, 2024
1 parent aa602cf commit 6a1cc5d
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 10 deletions.
6 changes: 3 additions & 3 deletions src/Jobs/AiAutofillJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ class AiAutofillJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, QueueableByBus, SerializesModels;

public function __construct(protected Model $model, protected array $autofill, protected array $autofillExclude = []) {}
public function __construct(public Model $model, public array $autofill = [], public array $autofillExclude = []) {}

public function handle()
{
if (empty($this->autofill)) {
if (!isset($this->autofill) || empty($this->autofill)) {
return;
}

Expand Down Expand Up @@ -104,7 +104,7 @@ public function handle()
public function middleware(): array
{
return [
(new WithoutOverlapping(self::class.':'.$this->model->{$this->model->getKeyName()}))
(new WithoutOverlapping(self::class . ':' . $this->model->{$this->model->getKeyName()}))
->expireAfter(40)
->releaseAfter(40)
->dontRelease(),
Expand Down
52 changes: 52 additions & 0 deletions tests/AiAutofillTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

use AshleyHindle\AiAutofill\Jobs\AiAutofillJob;
use AshleyHindle\AiAutofill\Tests\Models\ArticleNoAutofill;
use AshleyHindle\AiAutofill\Tests\Models\ArticleEmptyAutofill;
use AshleyHindle\AiAutofill\Tests\Models\ArticleExcludedAutofill;
use AshleyHindle\AiAutofill\Tests\Models\ArticleAutofill;
use Illuminate\Support\Facades\Queue;

it('doesn\'t autofill with a missing autofill property', function () {
Queue::fake();
$article = ArticleNoAutofill::create(['title' => 'My Article']);
$article->save();
Queue::assertNothingPushed();
});

it('doesn\'t autofill with an empty autofill property', function () {
Queue::fake();
$article = ArticleEmptyAutofill::create(['title' => 'My Article']);
$article->save();
Queue::assertNothingPushed();
});

it('autofills on model creation', function () {
Queue::fake();
$article = ArticleAutofill::create(['title' => 'My Article']);
$article->save();
Queue::assertPushed(AiAutofillJob::class);
});

it('doesn\'t autofill when not dirty', function () {
Queue::fake();
$article = ArticleAutofill::create(['title' => 'My Article']);
$article->save();
Queue::assertPushed(AiAutofillJob::class);

Queue::fake();
$article->title = 'My Article';
$article->save();
Queue::assertNothingPushed();
});

it('passed excluded properties to the job', function () {
Queue::fake();
$content = '### MY CONTENT IS VERY EASY TO SPOT ###';
$article = ArticleExcludedAutofill::create(['title' => 'My Article', 'content' => $content]);
$article->save();
Queue::assertPushed(function (AiAutofillJob $job) use ($content) {
return $job->autofill === ['tagline' => 'ridiculous click-bait tagline']
&& $job->autofillExclude === ['content'];
});
});
5 changes: 0 additions & 5 deletions tests/ExampleTest.php

This file was deleted.

81 changes: 81 additions & 0 deletions tests/Jobs/AiAutofillJobTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

use AshleyHindle\AiAutofill\Jobs\AiAutofillJob;
use AshleyHindle\AiAutofill\Tests\Models\ArticleNoAutofill;
use AshleyHindle\AiAutofill\Tests\Models\ArticleEmptyAutofill;
use AshleyHindle\AiAutofill\Tests\Models\ArticleExcludedAutofill;
use AshleyHindle\AiAutofill\Tests\Models\ArticleAutofill;
use OpenAI\Laravel\Facades\OpenAI;
use OpenAI\Responses\Chat\CreateResponse;
use OpenAI\Resources\Chat;

it('calls the OpenAI API once with the correct parameters', function () {
OpenAI::fake([
CreateResponse::fake([
'choices' => [
['message' => ['content' => '{"tagline":"ridiculous click-bait tagline"}']],
],
]),
]);

$article = new ArticleAutofill(['title' => 'Howdy']);
$article->saveQuietly();
AiAutofillJob::dispatch($article, ['tagline' => 'ridiculous click-bait tagline']);

OpenAI::assertSent(Chat::class, function (string $method, array $parameters): bool {
return $method === 'create' &&
$parameters['model'] === 'gpt-4o-mini' &&
$parameters['response_format']['type'] === 'json_schema' &&
str_contains($parameters['messages'][0]['content'], 'Howdy') &&
str_contains($parameters['messages'][0]['content'], 'ridiculous click-bait tagline');
});
});


it('calls the OpenAI API, without sharing excluded properties in the prompt', function () {
OpenAI::fake([
CreateResponse::fake([
'choices' => [
['message' => ['content' => '{"tagline":"ridiculous click-bait tagline"}']],
],
]),
]);

$content = '### MY CONTENT IS VERY EASY TO SPOT ###';
$article = new ArticleAutofill(['title' => 'Howdy', 'content' => $content]);
$article->saveQuietly();
AiAutofillJob::dispatch($article, ['tagline' => 'ridiculous click-bait tagline'], ['content']);

OpenAI::assertSent(Chat::class, function (string $method, array $parameters) use ($content): bool {
return $method === 'create' &&
$parameters['model'] === 'gpt-4o-mini' &&
$parameters['response_format']['type'] === 'json_schema' &&
str_contains($parameters['messages'][0]['content'], 'Howdy') &&
str_contains($parameters['messages'][0]['content'], 'ridiculous click-bait tagline') &&
!str_contains($parameters['messages'][0]['content'], $content);
});
});

it('does not call the OpenAI API if there is a missing or empty autofill property', function () {
OpenAI::fake([
CreateResponse::fake([
'choices' => [
['message' => ['content' => '{"tagline":"ridiculous click-bait tagline"}']],
],
]),
]);

$article = new ArticleNoAutofill(['title' => 'Howdy']);
$article->saveQuietly();
AiAutofillJob::dispatch($article); // MISSING

OpenAI::assertNotSent(Chat::class, function (string $method, array $parameters): bool {
return $method === 'create';
});

AiAutofillJob::dispatch($article, []); // EMPTY

OpenAI::assertNotSent(Chat::class, function (string $method, array $parameters): bool {
return $method === 'create';
});
});
16 changes: 16 additions & 0 deletions tests/Models/ArticleAutofill.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace AshleyHindle\AiAutofill\Tests\Models;

use Illuminate\Database\Eloquent\Model;
use AshleyHindle\AiAutofill\AiAutofill;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class ArticleAutofill extends Model
{
use AiAutofill, HasFactory;
protected $table = 'articles';

protected $autofill = ['tagline' => 'ridiculous click-bait tagline'];
protected $fillable = ['title', 'content', 'tagline', 'seo_description', 'tags'];
}
16 changes: 16 additions & 0 deletions tests/Models/ArticleEmptyAutofill.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace AshleyHindle\AiAutofill\Tests\Models;

use Illuminate\Database\Eloquent\Model;
use AshleyHindle\AiAutofill\AiAutofill;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class ArticleEmptyAutofill extends Model
{
use AiAutofill, HasFactory;
protected $table = 'articles';

protected $autofill = [];
protected $fillable = ['title'];
}
17 changes: 17 additions & 0 deletions tests/Models/ArticleExcludedAutofill.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace AshleyHindle\AiAutofill\Tests\Models;

use Illuminate\Database\Eloquent\Model;
use AshleyHindle\AiAutofill\AiAutofill;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class ArticleExcludedAutofill extends Model
{
use AiAutofill, HasFactory;
protected $table = 'articles';

protected $autofill = ['tagline' => 'ridiculous click-bait tagline'];
protected $autofillExclude = ['content'];
protected $fillable = ['title', 'content', 'tagline', 'seo_description', 'tags'];
}
15 changes: 15 additions & 0 deletions tests/Models/ArticleNoAutofill.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace AshleyHindle\AiAutofill\Tests\Models;

use Illuminate\Database\Eloquent\Model;
use AshleyHindle\AiAutofill\AiAutofill;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class ArticleNoAutofill extends Model
{
use AiAutofill, HasFactory;
protected $table = 'articles';

protected $fillable = ['title', 'content', 'tagline', 'seo_description', 'tags'];
}
17 changes: 15 additions & 2 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use AshleyHindle\AiAutofill\AiAutofillServiceProvider;
use Illuminate\Database\Eloquent\Factories\Factory;
use Orchestra\Testbench\TestCase as Orchestra;
use function Orchestra\Testbench\workbench_path;

class TestCase extends Orchestra
{
Expand All @@ -13,7 +14,14 @@ protected function setUp(): void
parent::setUp();

Factory::guessFactoryNamesUsing(
fn (string $modelName) => 'AshleyHindle\\AiAutofill\\Database\\Factories\\'.class_basename($modelName).'Factory'
fn(string $modelName) => 'AshleyHindle\\AiAutofill\\Database\\Factories\\' . class_basename($modelName) . 'Factory'
);
}

protected function defineDatabaseMigrations()
{
$this->loadMigrationsFrom(
workbench_path('database/migrations')
);
}

Expand All @@ -26,6 +34,11 @@ protected function getPackageProviders($app)

public function getEnvironmentSetUp($app)
{
config()->set('database.default', 'testing');
config()->set('database.default', 'testbench');
config()->set('database.connections.testbench', [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
]);
}
}
32 changes: 32 additions & 0 deletions workbench/database/migrations/1_create_articles_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('title')->nullable();
$table->text('content')->nullable();
$table->string('tagline')->nullable();
$table->text('seo_description')->nullable();
$table->json('tags')->nullable();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('articles');
}
};

0 comments on commit 6a1cc5d

Please sign in to comment.