Skip to content

Commit 2009123

Browse files
committed
tests: tests for search docs tool
1 parent 0e63584 commit 2009123

File tree

1 file changed

+226
-0
lines changed

1 file changed

+226
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Http\Client\PendingRequest;
6+
use Illuminate\Http\Client\Response;
7+
use Laravel\Boost\Mcp\Tools\SearchDocs;
8+
use Laravel\Mcp\Server\Tools\ToolResult;
9+
use Laravel\Roster\Enums\Packages;
10+
use Laravel\Roster\Package;
11+
use Laravel\Roster\PackageCollection;
12+
use Laravel\Roster\Roster;
13+
14+
test('it searches documentation successfully', function () {
15+
$packages = new PackageCollection([
16+
new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'),
17+
new Package(Packages::PEST, 'pestphp/pest', '2.0.0'),
18+
]);
19+
20+
$roster = Mockery::mock(Roster::class);
21+
$roster->shouldReceive('packages')->andReturn($packages);
22+
23+
$mockResponse = Mockery::mock(Response::class);
24+
$mockResponse->shouldReceive('successful')->andReturn(true);
25+
$mockResponse->shouldReceive('json')->andReturn([
26+
'results' => [
27+
['content' => 'Laravel documentation content'],
28+
['content' => 'Pest documentation content'],
29+
]
30+
]);
31+
32+
$mockClient = Mockery::mock(PendingRequest::class);
33+
$mockClient->shouldReceive('asJson')->andReturnSelf();
34+
$mockClient->shouldReceive('post')->andReturn($mockResponse);
35+
36+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
37+
$tool->shouldReceive('client')->andReturn($mockClient);
38+
39+
$result = $tool->handle(['queries' => 'authentication, testing']);
40+
41+
expect($result)->toBeInstanceOf(ToolResult::class);
42+
43+
$data = $result->toArray();
44+
expect($data['isError'])->toBeFalse();
45+
46+
$content = json_decode($data['content'][0]['text'], true);
47+
expect($content['knowledge_count'])->toBe(2);
48+
expect($content['knowledge'])->toContain('Laravel documentation content');
49+
expect($content['knowledge'])->toContain('Pest documentation content');
50+
expect($content['knowledge'])->toContain('---');
51+
});
52+
53+
test('it handles API error response', function () {
54+
$packages = new PackageCollection([
55+
new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'),
56+
]);
57+
58+
$roster = Mockery::mock(Roster::class);
59+
$roster->shouldReceive('packages')->andReturn($packages);
60+
61+
$mockResponse = Mockery::mock(Response::class);
62+
$mockResponse->shouldReceive('successful')->andReturn(false);
63+
$mockResponse->shouldReceive('status')->andReturn(500);
64+
$mockResponse->shouldReceive('body')->andReturn('API Error');
65+
66+
$mockClient = Mockery::mock(PendingRequest::class);
67+
$mockClient->shouldReceive('asJson')->andReturnSelf();
68+
$mockClient->shouldReceive('post')->andReturn($mockResponse);
69+
70+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
71+
$tool->shouldReceive('client')->andReturn($mockClient);
72+
73+
$result = $tool->handle(['queries' => 'authentication']);
74+
75+
expect($result)->toBeInstanceOf(ToolResult::class);
76+
77+
$data = $result->toArray();
78+
expect($data['isError'])->toBeTrue();
79+
expect($data['content'][0]['text'])->toBe('Failed to search documentation: API Error');
80+
});
81+
82+
test('it filters empty queries', function () {
83+
$packages = new PackageCollection([]);
84+
85+
$roster = Mockery::mock(Roster::class);
86+
$roster->shouldReceive('packages')->andReturn($packages);
87+
88+
$mockResponse = Mockery::mock(Response::class);
89+
$mockResponse->shouldReceive('successful')->andReturn(true);
90+
$mockResponse->shouldReceive('json')->andReturn(['results' => []]);
91+
92+
$mockClient = Mockery::mock(PendingRequest::class);
93+
$mockClient->shouldReceive('asJson')->andReturnSelf();
94+
$mockClient->shouldReceive('post')->withArgs(function($url, $payload) {
95+
return $url === 'https://boost.laravel.com/api/docs' &&
96+
$payload['queries'] === ['test'] &&
97+
empty($payload['packages']) &&
98+
$payload['token_limit'] === 10000;
99+
})->andReturn($mockResponse);
100+
101+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
102+
$tool->shouldReceive('client')->andReturn($mockClient);
103+
104+
$result = $tool->handle(['queries' => 'test### ###*### ']);
105+
106+
expect($result)->toBeInstanceOf(ToolResult::class);
107+
108+
$data = $result->toArray();
109+
expect($data['isError'])->toBeFalse();
110+
});
111+
112+
test('it formats package data correctly', function () {
113+
$packages = new PackageCollection([
114+
new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'),
115+
new Package(Packages::LIVEWIRE, 'livewire/livewire', '3.5.1'),
116+
]);
117+
118+
$roster = Mockery::mock(Roster::class);
119+
$roster->shouldReceive('packages')->andReturn($packages);
120+
121+
$mockResponse = Mockery::mock(Response::class);
122+
$mockResponse->shouldReceive('successful')->andReturn(true);
123+
$mockResponse->shouldReceive('json')->andReturn(['results' => []]);
124+
125+
$mockClient = Mockery::mock(PendingRequest::class);
126+
$mockClient->shouldReceive('asJson')->andReturnSelf();
127+
$mockClient->shouldReceive('post')->with(
128+
'https://boost.laravel.com/api/docs',
129+
Mockery::on(function ($payload) {
130+
return $payload['packages'] === [
131+
['name' => 'laravel/framework', 'version' => '11.x'],
132+
['name' => 'livewire/livewire', 'version' => '3.x']
133+
] && $payload['token_limit'] === 10000;
134+
})
135+
)->andReturn($mockResponse);
136+
137+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
138+
$tool->shouldReceive('client')->andReturn($mockClient);
139+
140+
$result = $tool->handle(['queries' => 'test']);
141+
142+
expect($result)->toBeInstanceOf(ToolResult::class);
143+
});
144+
145+
test('it handles empty results', function () {
146+
$packages = new PackageCollection([]);
147+
148+
$roster = Mockery::mock(Roster::class);
149+
$roster->shouldReceive('packages')->andReturn($packages);
150+
151+
$mockResponse = Mockery::mock(Response::class);
152+
$mockResponse->shouldReceive('successful')->andReturn(true);
153+
$mockResponse->shouldReceive('json')->andReturn(['results' => []]);
154+
155+
$mockClient = Mockery::mock(PendingRequest::class);
156+
$mockClient->shouldReceive('asJson')->andReturnSelf();
157+
$mockClient->shouldReceive('post')->andReturn($mockResponse);
158+
159+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
160+
$tool->shouldReceive('client')->andReturn($mockClient);
161+
162+
$result = $tool->handle(['queries' => 'nonexistent']);
163+
164+
expect($result)->toBeInstanceOf(ToolResult::class);
165+
166+
$data = $result->toArray();
167+
expect($data['isError'])->toBeFalse();
168+
169+
$content = json_decode($data['content'][0]['text'], true);
170+
expect($content['knowledge_count'])->toBe(0);
171+
expect($content['knowledge'])->toBe('');
172+
});
173+
174+
test('it uses custom token_limit when provided', function () {
175+
$packages = new PackageCollection([]);
176+
177+
$roster = Mockery::mock(Roster::class);
178+
$roster->shouldReceive('packages')->andReturn($packages);
179+
180+
$mockResponse = Mockery::mock(Response::class);
181+
$mockResponse->shouldReceive('successful')->andReturn(true);
182+
$mockResponse->shouldReceive('json')->andReturn(['results' => []]);
183+
184+
$mockClient = Mockery::mock(PendingRequest::class);
185+
$mockClient->shouldReceive('asJson')->andReturnSelf();
186+
$mockClient->shouldReceive('post')->with(
187+
'https://boost.laravel.com/api/docs',
188+
Mockery::on(function ($payload) {
189+
return $payload['token_limit'] === 5000;
190+
})
191+
)->andReturn($mockResponse);
192+
193+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
194+
$tool->shouldReceive('client')->andReturn($mockClient);
195+
196+
$result = $tool->handle(['queries' => 'test', 'token_limit' => 5000]);
197+
198+
expect($result)->toBeInstanceOf(ToolResult::class);
199+
});
200+
201+
test('it caps token_limit at maximum of 1000000', function () {
202+
$packages = new PackageCollection([]);
203+
204+
$roster = Mockery::mock(Roster::class);
205+
$roster->shouldReceive('packages')->andReturn($packages);
206+
207+
$mockResponse = Mockery::mock(Response::class);
208+
$mockResponse->shouldReceive('successful')->andReturn(true);
209+
$mockResponse->shouldReceive('json')->andReturn(['results' => []]);
210+
211+
$mockClient = Mockery::mock(PendingRequest::class);
212+
$mockClient->shouldReceive('asJson')->andReturnSelf();
213+
$mockClient->shouldReceive('post')->with(
214+
'https://boost.laravel.com/api/docs',
215+
Mockery::on(function ($payload) {
216+
return $payload['token_limit'] === 1000000; // Should be capped at 1M
217+
})
218+
)->andReturn($mockResponse);
219+
220+
$tool = Mockery::mock(SearchDocs::class, [$roster])->makePartial();
221+
$tool->shouldReceive('client')->andReturn($mockClient);
222+
223+
$result = $tool->handle(['queries' => 'test', 'token_limit' => 2000000]); // Request 2M but get capped at 1M
224+
225+
expect($result)->toBeInstanceOf(ToolResult::class);
226+
});

0 commit comments

Comments
 (0)