File: /home/xedaptot/ai.naniguide.com/tests/Feature/CustomerVerificationServerServiceTest.php
<?php
/**
* Feature test for the customer-side VerificationServerService — read aggregator
* powering the rich-redesigned /rui/sending/verification-servers page.
*
* Guards:
* - headerMeta() returns the 4-key shape (total/active/inactive/vendors)
* - sidebarStats() returns DTO with header meta + coverage + capacity
* - list() honours keyword + status filters and sort whitelist
* - GET /rui/sending/verification-servers renders 200 with rich-redesign markers
* (banner-led, no stats-strip, 4-card rail, chart palette in scripts)
*/
use App\Model\Customer;
use App\Model\EmailVerificationServer;
use App\Services\Customer\VerificationServerService;
use App\Services\Plans\Entitlements\EntitlementKey;
use App\Services\Plans\Gates\EntitlementGate;
uses(\Tests\TestCase::class);
beforeEach(function () {
$hostId = EmailVerificationServer::query()->whereNotNull('customer_id')->value('customer_id');
$this->customer = $hostId
? Customer::find($hostId)
: Customer::first();
if (! $this->customer) {
$this->markTestSkipped('No customer in DB — run DemoSeeder first');
}
$this->service = app(VerificationServerService::class);
});
test('headerMeta returns total/active/inactive/vendors integers', function () {
$meta = $this->service->headerMeta($this->customer);
expect($meta)->toHaveKeys(['total', 'active', 'inactive', 'vendors']);
foreach (['total', 'active', 'inactive', 'vendors'] as $k) {
expect($meta[$k])->toBeInt();
}
expect($meta['active'] + $meta['inactive'])->toBe($meta['total']);
});
test('sidebarStats returns DTO with all three pre-shaped payloads', function () {
$dto = $this->service->sidebarStats($this->customer);
expect($dto)->toBeInstanceOf(\App\Dto\Refactor\VerificationServer\VerificationServerSidebarStatsDto::class);
expect($dto->headerMeta)->toHaveKeys(['total', 'active', 'inactive', 'vendors']);
expect($dto->coverage)->toHaveKeys(['used_vendor_ids', 'catalog']);
expect($dto->coverage['catalog'])->toBeArray();
foreach ($dto->coverage['catalog'] as $entry) {
expect($entry)->toHaveKeys(['id', 'name', 'connected', 'count']);
expect($entry['connected'])->toBeBool();
}
expect($dto->combinedCapacity)->toHaveKeys(['value', 'unit', 'base', 'formatted']);
expect($dto->combinedCapacity['value'])->toBeInt();
});
test('coverage catalog lists connected vendors first', function () {
$dto = $this->service->sidebarStats($this->customer);
$catalog = $dto->coverage['catalog'];
if (empty($catalog)) {
$this->markTestSkipped('verification.services config empty');
}
$sawDisconnectedAlready = false;
foreach ($catalog as $entry) {
if (! $entry['connected']) {
$sawDisconnectedAlready = true;
continue;
}
// Once we've seen a disconnected entry, no connected entry should follow.
expect($sawDisconnectedAlready)->toBeFalse();
}
});
test('list honours status=active — only STATUS_ACTIVE rows', function () {
$list = $this->service->list($this->customer, null, 'active');
foreach ($list->items() as $server) {
expect($server->status)->toBe(EmailVerificationServer::STATUS_ACTIVE);
}
});
test('list rejects unknown sort column', function () {
$list = $this->service->list($this->customer, null, null, 'pwned_column', 'asc');
expect($list)->toBeInstanceOf(\Illuminate\Contracts\Pagination\LengthAwarePaginator::class);
});
test('GET /rui/sending/verification-servers renders 200 with rich-redesign markers', function () {
if (! EntitlementGate::allows($this->customer, EntitlementKey::HAS_OWN_EMAIL_VERIFICATION_SERVER)) {
$this->markTestSkipped('Customer plan disallows own verification server');
}
$user = $this->customer->user;
if (! $user) {
$this->markTestSkipped('No user attached to customer');
}
$resp = $this->actingAs($user)->get(route('refactor.sending.verification_servers'));
$resp->assertStatus(200);
$resp->assertSee('mc-banner mc-banner-open', false);
$resp->assertSee('mc-banner-meta', false);
$resp->assertSee('mc-page-grid', false);
$resp->assertSee('mc-page-rail', false);
$resp->assertSee('rui-verifiers-page-grid', false);
$resp->assertSee('rui-verifiers-rail-card', false);
// Banner H2 must NOT duplicate the page H1.
$resp->assertDontSee('>Email verification servers<', false);
});
test('GET listing renders rich row partial', function () {
if (! EntitlementGate::allows($this->customer, EntitlementKey::HAS_OWN_EMAIL_VERIFICATION_SERVER)) {
$this->markTestSkipped('Customer plan disallows own verification server');
}
$user = $this->customer->user;
if (! $user) {
$this->markTestSkipped('No user attached to customer');
}
$resp = $this->actingAs($user)->get(route('refactor.sending.verification_servers_listing'));
$resp->assertStatus(200);
if (EmailVerificationServer::where('customer_id', $this->customer->id)->count() > 0) {
$resp->assertSee('rui-verifiers-list-name-cell', false);
$resp->assertSee('rui-verifiers-list-sub', false);
}
});