@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Client\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Livewire\Livewire;
|
||||
use Modules\AiAgent\Filament\Pages\ManageSuggestions;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
beforeEach(function () {
|
||||
config([
|
||||
'services.bnfexpress.ai_api_url' => 'https://bnfexpress.test',
|
||||
'services.bnfexpress.client_id' => 'ev_admin',
|
||||
'services.bnfexpress.client_secret' => 'test-secret',
|
||||
]);
|
||||
|
||||
Permission::findOrCreate('manage_ai_agent', 'web');
|
||||
|
||||
$this->admin = User::factory()->create()->givePermissionTo(['manage_ai_agent']);
|
||||
$this->actingAs($this->admin);
|
||||
});
|
||||
|
||||
test('a user without manage_ai_agent cannot access it', function () {
|
||||
$this->actingAs(User::factory()->create());
|
||||
|
||||
expect(ManageSuggestions::canAccess())->toBeFalse();
|
||||
});
|
||||
|
||||
test('it renders and lists suggestions from the client', function () {
|
||||
Http::fake(['bnfexpress.test/*' => Http::response([
|
||||
['id' => 1, 'text_display' => 'How do I charge my EV?', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'manual', 'updated_at' => now()->toIso8601String()],
|
||||
])]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->assertOk()
|
||||
->loadTable()
|
||||
->assertSee('How do I charge my EV?');
|
||||
|
||||
Http::assertSent(fn (Request $request) => str_contains($request->url(), '/admin/suggestions') && $request->method() === 'GET');
|
||||
});
|
||||
|
||||
test('creating a suggestion calls createSuggestion and shows a success notification', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match ($request->method()) {
|
||||
'POST' => Http::response(['id' => 1], 201),
|
||||
default => Http::response([]),
|
||||
}]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('create', data: ['text_display' => 'New phrase', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'admin'])
|
||||
->assertNotified('Suggestion created');
|
||||
|
||||
Http::assertSent(fn (Request $request) => $request->method() === 'POST'
|
||||
&& $request->url() === 'https://bnfexpress.test/admin/suggestions'
|
||||
&& $request['text_display'] === 'New phrase');
|
||||
});
|
||||
|
||||
test('a failed create surfaces the gateway detail message', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match ($request->method()) {
|
||||
'POST' => Http::response(['detail' => 'text_display is required.'], 422),
|
||||
default => Http::response([]),
|
||||
}]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('create', data: ['text_display' => 'New phrase', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'admin'])
|
||||
->assertNotified('Failed to create suggestion');
|
||||
});
|
||||
|
||||
test('createMany splits pasted lines into batch items and shows the created/skipped result', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match (true) {
|
||||
str_contains($request->url(), '/admin/suggestions/batch') => Http::response(['created' => 2, 'skipped' => 0, 'trie_rebuilt' => true]),
|
||||
default => Http::response([]),
|
||||
}]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('createMany', data: ['items_raw' => "First phrase\nSecond phrase\n\n", 'lang' => 'en', 'intent' => null])
|
||||
->assertNotified('2 created, 0 skipped');
|
||||
|
||||
Http::assertSent(fn (Request $request) => str_contains($request->url(), '/admin/suggestions/batch')
|
||||
&& $request['items'] === [
|
||||
['text' => 'First phrase', 'lang' => 'en'],
|
||||
['text' => 'Second phrase', 'lang' => 'en'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('deleting a suggestion calls deleteSuggestion and shows a success notification', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match ($request->method()) {
|
||||
'DELETE' => Http::response([]),
|
||||
default => Http::response([
|
||||
['id' => 1, 'text_display' => 'To delete', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'manual', 'updated_at' => now()->toIso8601String()],
|
||||
]),
|
||||
}]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('delete', 1)
|
||||
->assertNotified('Suggestion deleted');
|
||||
|
||||
Http::assertSent(fn (Request $request) => $request->method() === 'DELETE' && str_contains($request->url(), '/admin/suggestions/1'));
|
||||
});
|
||||
|
||||
test('deleteSelected bulk action calls batchDeleteSuggestions with just the selected ids', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match (true) {
|
||||
$request->method() === 'DELETE' && str_contains($request->url(), '/admin/suggestions/batch') => Http::response(['deleted' => 2, 'skipped' => 0]),
|
||||
default => Http::response([
|
||||
['id' => 1, 'text_display' => 'A', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'manual', 'updated_at' => now()->toIso8601String()],
|
||||
['id' => 2, 'text_display' => 'B', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'manual', 'updated_at' => now()->toIso8601String()],
|
||||
]),
|
||||
}]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableBulkAction('deleteSelected', [1, 2])
|
||||
->assertNotified('2 deleted, 0 skipped');
|
||||
|
||||
Http::assertSent(fn (Request $request) => $request->method() === 'DELETE'
|
||||
&& str_contains($request->url(), '/admin/suggestions/batch')
|
||||
&& $request['ids'] === [1, 2]);
|
||||
});
|
||||
|
||||
test('sync sets job state and polling chains a reload-index call on finished', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match (true) {
|
||||
str_contains($request->url(), '/sync-chroma/job-1') => Http::response(['status' => 'finished', 'result' => ['synced' => 3]]),
|
||||
str_contains($request->url(), '/sync-chroma') => Http::response(['job_id' => 'job-1'], 202),
|
||||
str_contains($request->url(), '/reload-index') => Http::response(['trie_rebuilt' => true]),
|
||||
default => Http::response([]),
|
||||
}]);
|
||||
|
||||
$test = Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('sync')
|
||||
->assertSet('syncJobId', 'job-1')
|
||||
->assertSet('syncStatus', 'queued');
|
||||
|
||||
$test->call('pollSyncStatus')
|
||||
->assertSet('syncJobId', null)
|
||||
->assertSet('syncStatus', 'finished')
|
||||
->assertNotified('Sync completed and index reloaded');
|
||||
|
||||
Http::assertSent(fn (Request $request) => str_contains($request->url(), '/admin/suggestions/reload-index'));
|
||||
});
|
||||
|
||||
test('a failed sync job notifies danger and stops polling', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match (true) {
|
||||
str_contains($request->url(), '/sync-chroma/job-1') => Http::response(['status' => 'failed', 'result' => null]),
|
||||
str_contains($request->url(), '/sync-chroma') => Http::response(['job_id' => 'job-1'], 202),
|
||||
default => Http::response([]),
|
||||
}]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('sync')
|
||||
->call('pollSyncStatus')
|
||||
->assertSet('syncJobId', null)
|
||||
->assertNotified('Sync failed');
|
||||
});
|
||||
|
||||
test('reloadIndex calls reloadSuggestionIndex directly', function () {
|
||||
Http::fake(['bnfexpress.test/*' => Http::response(['trie_rebuilt' => true])]);
|
||||
|
||||
Livewire::test(ManageSuggestions::class)
|
||||
->loadTable()
|
||||
->callTableAction('reloadIndex')
|
||||
->assertNotified('Index reloaded');
|
||||
|
||||
Http::assertSent(fn (Request $request) => str_contains($request->url(), '/admin/suggestions/reload-index'));
|
||||
});
|
||||
|
||||
test('syncEmbedding and deleteEmbedding row actions call the right per-id endpoint', function () {
|
||||
Http::fake(['bnfexpress.test/*' => fn (Request $request) => match (true) {
|
||||
str_contains($request->url(), '/1/sync-chroma') => Http::response(['synced' => true]),
|
||||
str_contains($request->url(), '/1/chroma') => Http::response([]),
|
||||
default => Http::response([
|
||||
['id' => 1, 'text_display' => 'A', 'lang' => 'en', 'intent' => null, 'weight' => 0, 'source' => 'manual', 'updated_at' => now()->toIso8601String()],
|
||||
]),
|
||||
}]);
|
||||
|
||||
$test = Livewire::test(ManageSuggestions::class)->loadTable();
|
||||
|
||||
$test->callTableAction('syncEmbedding', 1)->assertNotified('Embedding synced');
|
||||
$test->callTableAction('deleteEmbedding', 1)->assertNotified('Embedding deleted');
|
||||
|
||||
Http::assertSent(fn (Request $request) => str_contains($request->url(), '/admin/suggestions/1/sync-chroma') && $request->method() === 'POST');
|
||||
Http::assertSent(fn (Request $request) => str_contains($request->url(), '/admin/suggestions/1/chroma') && $request->method() === 'DELETE');
|
||||
});
|
||||
Reference in New Issue
Block a user