lthn.io/app/Mod/Names/Tests/Feature/NamesApiTest.php
Claude 0241e1f4a6
feat: TestCase base class + test infrastructure
tests/TestCase.php bootstraps app via Core\Boot::app() with kernel
bootstrap. DatabaseTransactions for test isolation. PHPUnit config
with array cache/session. 12 tests written, unit tests pass.
HTTP endpoint tests need chain daemon mock to run standalone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:17:54 +01:00

154 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Mod\Names\Tests\Feature;
use Mod\Names\Actions\CheckAvailability;
use Mod\Names\Actions\SubmitClaim;
use Mod\Names\Models\NameActivity;
use Mod\Names\Models\NameClaim;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class NamesApiTest extends TestCase
{
use DatabaseTransactions;
public function test_check_availability_returns_correct_structure(): void
{
$result = CheckAvailability::run('testname123');
$this->assertArrayHasKey('name', $result);
$this->assertArrayHasKey('available', $result);
$this->assertArrayHasKey('reserved', $result);
$this->assertArrayHasKey('fqdn', $result);
$this->assertEquals('testname123.lthn', $result['fqdn']);
}
public function test_invalid_name_returns_unavailable(): void
{
$result = CheckAvailability::run('AB');
$this->assertFalse($result['available']);
}
public function test_submit_claim_creates_record(): void
{
$claim = SubmitClaim::run([
'name' => 'claimtest',
'email' => 'test@example.com',
]);
$this->assertInstanceOf(NameClaim::class, $claim);
$this->assertEquals('claimtest', $claim->name);
$this->assertEquals('pending', $claim->status);
$this->assertNotEmpty($claim->claim_id);
$this->assertEquals(12, strlen($claim->claim_id));
$this->assertDatabaseHas('name_claims', [
'name' => 'claimtest',
'email' => 'test@example.com',
'status' => 'pending',
]);
}
public function test_submit_claim_logs_activity(): void
{
SubmitClaim::run([
'name' => 'actlogtest',
'email' => 'log@example.com',
]);
$this->assertDatabaseHas('name_activity', [
'name' => 'actlogtest',
'event' => 'claimed',
]);
}
public function test_duplicate_claim_rejected(): void
{
SubmitClaim::run([
'name' => 'dupetest1',
'email' => 'first@example.com',
]);
$this->expectException(\Illuminate\Validation\ValidationException::class);
SubmitClaim::run([
'name' => 'dupetest1',
'email' => 'second@example.com',
]);
}
public function test_claim_with_invalid_email_rejected(): void
{
$this->expectException(\Illuminate\Validation\ValidationException::class);
SubmitClaim::run([
'name' => 'emailtest',
'email' => 'not-an-email',
]);
}
public function test_claim_with_short_name_rejected(): void
{
$this->expectException(\Illuminate\Validation\ValidationException::class);
SubmitClaim::run([
'name' => 'abc',
'email' => 'test@example.com',
]);
}
public function test_name_claim_model_scopes(): void
{
$pending = NameClaim::create(['name' => 'scopep1', 'email' => 'a@b.com', 'status' => 'pending', 'claim_id' => 'scpaaa']);
$approved = NameClaim::create(['name' => 'scopea1', 'email' => 'a@b.com', 'status' => 'approved', 'claim_id' => 'scpbbb']);
$this->assertTrue(NameClaim::pending()->where('id', $pending->id)->exists());
$this->assertTrue(NameClaim::approved()->where('id', $approved->id)->exists());
$this->assertFalse(NameClaim::pending()->where('id', $approved->id)->exists());
}
public function test_name_activity_log(): void
{
$activity = NameActivity::log('testlog', 'registered', [
'address' => 'iTHN...',
], '1.2.3.4');
$this->assertEquals('testlog', $activity->name);
$this->assertEquals('registered', $activity->event);
$this->assertNotNull($activity->ip_hash);
$this->assertNotEquals('1.2.3.4', $activity->ip_hash); // Hashed
$this->assertEquals(['address' => 'iTHN...'], $activity->properties);
}
public function test_available_endpoint_returns_json(): void
{
$response = $this->getJson('/v1/names/available/apiendtest');
$response->assertOk()
->assertJsonStructure(['name', 'available', 'reserved', 'fqdn']);
}
public function test_claim_endpoint_returns_201(): void
{
$response = $this->postJson('/v1/names/claim', [
'name' => 'endpointtest',
'email' => 'endpoint@test.com',
]);
$response->assertStatus(201)
->assertJsonStructure(['data' => ['claim_id', 'name', 'fqdn', 'status']]);
}
public function test_claim_endpoint_validates_input(): void
{
$response = $this->postJson('/v1/names/claim', [
'name' => 'ab',
'email' => 'bad',
]);
$response->assertStatus(422);
}
}