4 - Add Page and PageLink models with factories and unit tests
This commit is contained in:
parent
bc535c8c0b
commit
424ad2ff78
6 changed files with 293 additions and 0 deletions
51
app/Models/Page.php
Normal file
51
app/Models/Page.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\PageStatusEnum;
|
||||
use Database\Factories\PageFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Lvl0\FediDiscover\Models\Instance;
|
||||
|
||||
class Page extends Model
|
||||
{
|
||||
/** @use HasFactory<PageFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'url',
|
||||
'status',
|
||||
'title',
|
||||
'instance_id',
|
||||
'posted_at',
|
||||
'fetched_at',
|
||||
'failed_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'status' => PageStatusEnum::class,
|
||||
'posted_at' => 'datetime',
|
||||
'fetched_at' => 'datetime',
|
||||
'failed_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function instance(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Instance::class);
|
||||
}
|
||||
|
||||
public function outgoingLinks(): HasMany
|
||||
{
|
||||
return $this->hasMany(PageLink::class, 'source_page_id');
|
||||
}
|
||||
|
||||
public function incomingLinks(): HasMany
|
||||
{
|
||||
return $this->hasMany(PageLink::class, 'target_page_id');
|
||||
}
|
||||
}
|
||||
31
app/Models/PageLink.php
Normal file
31
app/Models/PageLink.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\PageLinkFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class PageLink extends Model
|
||||
{
|
||||
/** @use HasFactory<PageLinkFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'source_page_id',
|
||||
'target_page_id',
|
||||
];
|
||||
|
||||
public function sourcePage(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Page::class, 'source_page_id');
|
||||
}
|
||||
|
||||
public function targetPage(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Page::class, 'target_page_id');
|
||||
}
|
||||
}
|
||||
26
database/factories/PageFactory.php
Normal file
26
database/factories/PageFactory.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\PageStatusEnum;
|
||||
use App\Models\Page;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Page>
|
||||
*/
|
||||
class PageFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'url' => fake()->url(),
|
||||
'status' => PageStatusEnum::Discovered,
|
||||
];
|
||||
}
|
||||
}
|
||||
34
database/factories/PageLinkFactory.php
Normal file
34
database/factories/PageLinkFactory.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Page;
|
||||
use App\Models\PageLink;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<PageLink>
|
||||
*/
|
||||
class PageLinkFactory extends Factory
|
||||
{
|
||||
public function definition(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function withSource(Page $page): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'source_page_id' => $page->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function withTarget(Page $page): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'target_page_id' => $page->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
52
tests/Unit/Models/PageLinkTest.php
Normal file
52
tests/Unit/Models/PageLinkTest.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Models;
|
||||
|
||||
use App\Models\Page;
|
||||
use App\Models\PageLink;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PageLinkTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_page_link_model_fillable_fields_and_relationships(): void
|
||||
{
|
||||
$source = Page::factory()->create(['url' => 'https://source.example.com/post/1']);
|
||||
$target = Page::factory()->create(['url' => 'https://target.example.com/page/2']);
|
||||
|
||||
$link = PageLink::create([
|
||||
'source_page_id' => $source->id,
|
||||
'target_page_id' => $target->id,
|
||||
]);
|
||||
|
||||
$fresh = $link->fresh();
|
||||
|
||||
$this->assertNotNull($fresh);
|
||||
$this->assertSame($source->id, $fresh->source_page_id);
|
||||
$this->assertSame($target->id, $fresh->target_page_id);
|
||||
|
||||
$this->assertInstanceOf(Page::class, $fresh->sourcePage);
|
||||
$this->assertSame($source->id, $fresh->sourcePage->id);
|
||||
|
||||
$this->assertInstanceOf(Page::class, $fresh->targetPage);
|
||||
$this->assertSame($target->id, $fresh->targetPage->id);
|
||||
}
|
||||
|
||||
public function test_page_link_factory_with_source_and_target_methods_create_a_link(): void
|
||||
{
|
||||
$source = Page::factory()->create(['url' => 'https://source.example.com/post/1']);
|
||||
$target = Page::factory()->create(['url' => 'https://target.example.com/page/2']);
|
||||
|
||||
$link = PageLink::factory()
|
||||
->withSource($source)
|
||||
->withTarget($target)
|
||||
->create();
|
||||
|
||||
$this->assertSame($source->id, $link->source_page_id);
|
||||
$this->assertSame($target->id, $link->target_page_id);
|
||||
}
|
||||
}
|
||||
99
tests/Unit/Models/PageTest.php
Normal file
99
tests/Unit/Models/PageTest.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Models;
|
||||
|
||||
use App\Enums\PageStatusEnum;
|
||||
use App\Models\Page;
|
||||
use App\Models\PageLink;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Lvl0\FediDiscover\Config\InstanceType;
|
||||
use Lvl0\FediDiscover\Models\Instance;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PageTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_page_model_fillable_fields_can_be_mass_assigned(): void
|
||||
{
|
||||
$page = Page::create([
|
||||
'url' => 'https://example.com/article',
|
||||
'status' => 'discovered',
|
||||
'title' => 'An Example Article',
|
||||
'instance_id' => null,
|
||||
'posted_at' => null,
|
||||
'fetched_at' => null,
|
||||
]);
|
||||
|
||||
$fresh = $page->fresh();
|
||||
|
||||
$this->assertNotNull($fresh);
|
||||
$this->assertSame('https://example.com/article', $fresh->url);
|
||||
$this->assertSame('An Example Article', $fresh->title);
|
||||
$this->assertNull($fresh->instance_id);
|
||||
}
|
||||
|
||||
public function test_page_instance_relationship_returns_the_owning_instance(): void
|
||||
{
|
||||
$instance = Instance::factory()
|
||||
->type(InstanceType::Mastodon)
|
||||
->enabled()
|
||||
->create();
|
||||
|
||||
$page = Page::create([
|
||||
'url' => 'https://example.com/post/1',
|
||||
'status' => 'discovered',
|
||||
'instance_id' => $instance->id,
|
||||
]);
|
||||
|
||||
$fresh = $page->fresh();
|
||||
|
||||
$this->assertInstanceOf(Instance::class, $fresh->instance);
|
||||
$this->assertSame($instance->id, $fresh->instance->id);
|
||||
}
|
||||
|
||||
public function test_page_outgoing_and_incoming_links_relationships(): void
|
||||
{
|
||||
$source = Page::factory()->create(['url' => 'https://example.com/source']);
|
||||
$target = Page::factory()->create(['url' => 'https://example.com/target']);
|
||||
|
||||
PageLink::create([
|
||||
'source_page_id' => $source->id,
|
||||
'target_page_id' => $target->id,
|
||||
]);
|
||||
|
||||
$freshSource = $source->fresh();
|
||||
$freshTarget = $target->fresh();
|
||||
|
||||
$this->assertCount(1, $freshSource->outgoingLinks);
|
||||
$this->assertCount(0, $freshSource->incomingLinks);
|
||||
$this->assertCount(1, $freshTarget->incomingLinks);
|
||||
$this->assertCount(0, $freshTarget->outgoingLinks);
|
||||
|
||||
$this->assertSame($source->id, $freshTarget->incomingLinks->first()->source_page_id);
|
||||
$this->assertSame($target->id, $freshSource->outgoingLinks->first()->target_page_id);
|
||||
}
|
||||
|
||||
public function test_page_status_is_cast_to_enum(): void
|
||||
{
|
||||
$cases = [
|
||||
['string' => 'discovered', 'enum' => PageStatusEnum::Discovered],
|
||||
['string' => 'fetched', 'enum' => PageStatusEnum::Fetched],
|
||||
['string' => 'failed', 'enum' => PageStatusEnum::Failed],
|
||||
];
|
||||
|
||||
foreach ($cases as ['string' => $raw, 'enum' => $expected]) {
|
||||
$page = Page::create([
|
||||
'url' => 'https://example.com/' . $raw,
|
||||
'status' => $raw,
|
||||
]);
|
||||
|
||||
$fresh = $page->fresh();
|
||||
|
||||
$this->assertInstanceOf(PageStatusEnum::class, $fresh->status, "status '{$raw}' should cast to PageStatusEnum");
|
||||
$this->assertSame($expected, $fresh->status, "status '{$raw}' should equal PageStatusEnum::{$expected->name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue