add suggestion management
PHP Tests / php-tests (push) Waiting to run

This commit is contained in:
Nyan Lin Paing
2026-09-01 00:16:17 +07:00
parent b8d31e3dc4
commit 31ed52500a
12 changed files with 1226 additions and 5 deletions
@@ -74,6 +74,16 @@ test('a non-2xx response surfaces the gateway detail message', function () use (
(new BnfexpressAdminClient($config))->getFaq(999);
})->throws(BnfexpressApiException::class, 'FAQ not found.');
test('a FastAPI validation error (detail as a list of objects) is flattened into a readable message', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response([
'detail' => [
['type' => 'int_parsing', 'loc' => ['path', 'suggestion_id'], 'msg' => 'Input should be a valid integer, unable to parse string as an integer', 'input' => 'batch'],
],
], 422)]);
(new BnfexpressAdminClient($config))->getSuggestion('batch');
})->throws(BnfexpressApiException::class, 'Input should be a valid integer, unable to parse string as an integer');
test('deleteFaq signs a bodyless DELETE request', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['deleted' => true])]);
@@ -85,3 +95,114 @@ test('deleteFaq signs a bodyless DELETE request', function () use ($config) {
&& assertSignedCorrectly($request, 'DELETE', '/admin/faqs/5', '', $config['client_secret']);
});
});
test('createSuggestion sends text_display/lang/intent/weight/source', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['id' => 1], 201)]);
(new BnfexpressAdminClient($config))->createSuggestion('How do I charge?', 'en', 'charging', 5, 'manual');
$rawBody = json_encode([
'text_display' => 'How do I charge?',
'lang' => 'en',
'intent' => 'charging',
'weight' => 5,
'source' => 'manual',
]);
Http::assertSent(fn ($request) => $request->url() === 'https://bnfexpress.test/admin/suggestions'
&& $request->method() === 'POST'
&& $request->body() === $rawBody);
});
test('updateSuggestion only sends the given fields', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['id' => 1])]);
(new BnfexpressAdminClient($config))->updateSuggestion(1, weight: 10);
Http::assertSent(fn ($request) => $request->body() === json_encode(['weight' => 10]));
});
test('batchCreateSuggestions posts items and returns the created/skipped/trie_rebuilt result', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['created' => 2, 'skipped' => 1, 'trie_rebuilt' => true])]);
$result = (new BnfexpressAdminClient($config))->batchCreateSuggestions([
['text' => 'a', 'lang' => 'en'],
['text' => 'b', 'lang' => 'en', 'intent' => 'x'],
]);
expect($result)->toBe(['created' => 2, 'skipped' => 1, 'trie_rebuilt' => true]);
Http::assertSent(fn ($request) => $request->url() === 'https://bnfexpress.test/admin/suggestions/batch'
&& $request->method() === 'POST'
&& $request['items'] === [
['text' => 'a', 'lang' => 'en'],
['text' => 'b', 'lang' => 'en', 'intent' => 'x'],
]);
});
test('batchDeleteSuggestions sends a JSON body on DELETE and signs it', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['deleted' => 2, 'skipped' => 0])]);
$result = (new BnfexpressAdminClient($config))->batchDeleteSuggestions([1, 2]);
$rawBody = json_encode(['ids' => [1, 2]]);
expect($result)->toBe(['deleted' => 2, 'skipped' => 0]);
Http::assertSent(function ($request) use ($config, $rawBody) {
return $request->url() === 'https://bnfexpress.test/admin/suggestions/batch'
&& $request->method() === 'DELETE'
&& $request->body() === $rawBody
&& assertSignedCorrectly($request, 'DELETE', '/admin/suggestions/batch', $rawBody, $config['client_secret']);
});
});
test('listSuggestionMisses filters by was_used', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response([])]);
(new BnfexpressAdminClient($config))->listSuggestionMisses(wasUsed: false, limit: 25);
Http::assertSent(fn ($request) => $request->url() === 'https://bnfexpress.test/admin/suggestion-misses?was_used=0&limit=25'
|| $request->url() === 'https://bnfexpress.test/admin/suggestion-misses?was_used=&limit=25');
});
test('promoteSuggestionMisses posts miss_ids with an optional lang/intent override', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['created' => 1, 'skipped' => 0, 'trie_rebuilt' => true])]);
$result = (new BnfexpressAdminClient($config))->promoteSuggestionMisses([1, 2], lang: 'my');
expect($result)->toBe(['created' => 1, 'skipped' => 0, 'trie_rebuilt' => true]);
Http::assertSent(fn ($request) => $request->url() === 'https://bnfexpress.test/admin/suggestion-misses/promote'
&& $request->method() === 'POST'
&& $request->body() === json_encode(['miss_ids' => [1, 2], 'lang' => 'my']));
});
test('syncSuggestions triggers a sync-chroma job and returns the job id', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['job_id' => 'abc-123'], 202)]);
$result = (new BnfexpressAdminClient($config))->syncSuggestions();
expect($result)->toBe(['job_id' => 'abc-123']);
Http::assertSent(fn ($request) => $request->url() === 'https://bnfexpress.test/admin/suggestions/sync-chroma'
&& $request->method() === 'POST');
});
test('getSuggestionSyncStatus polls the job status endpoint', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response(['status' => 'finished', 'result' => ['synced' => 3]])]);
$result = (new BnfexpressAdminClient($config))->getSuggestionSyncStatus('abc-123');
expect($result)->toBe(['status' => 'finished', 'result' => ['synced' => 3]]);
Http::assertSent(fn ($request) => $request->url() === 'https://bnfexpress.test/admin/suggestions/sync-chroma/abc-123'
&& $request->method() === 'GET');
});
test('deleteSuggestionEmbedding signs a bodyless DELETE request', function () use ($config) {
Http::fake(['bnfexpress.test/*' => Http::response([])]);
(new BnfexpressAdminClient($config))->deleteSuggestionEmbedding(5);
Http::assertSent(function ($request) use ($config) {
return $request->url() === 'https://bnfexpress.test/admin/suggestions/5/chroma'
&& $request->method() === 'DELETE'
&& assertSignedCorrectly($request, 'DELETE', '/admin/suggestions/5/chroma', '', $config['client_secret']);
});
});