Testing
The package talks to X through Laravel’s HTTP client only, so Http::fake() covers every call.
Fake the two endpoints
use Darvis\ApiX\XClient;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
it('announces a release on X', function () {
config([
'api_x.credentials.access_token' => 'token',
'api_x.credentials.access_token_secret' => 'secret',
'api_x.credentials.consumer_key' => 'key',
'api_x.credentials.consumer_secret' => 'secret',
]);
Http::fake([
'api.x.com/2/media/upload' => Http::response(['data' => ['id' => '10']]),
'api.x.com/2/tweets' => Http::response(['data' => ['id' => '20']], 201),
]);
$result = app(XClient::class)->post('Released 1.0.0', base_path('tests/fixtures/card.png'));
expect($result->url())->toBe('https://x.com/i/web/status/20');
Http::assertSent(fn (Request $request) => $request->url() === 'https://api.x.com/2/tweets'
&& $request['media'] === ['media_ids' => ['10']]);
});
Dry runs
config(['api_x.dry_run' => true]) makes every post a dry run: every check runs and nothing is sent. Assert with Http::assertNothingSent().
The daily limit
The limit is counted in the default cache store. Use the array store in tests so every test starts at zero.
The MCP tool
use Darvis\ApiX\Mcp\Tools\PostUpdate;
use Darvis\ApiX\Mcp\XServer;
XServer::tool(PostUpdate::class, ['text' => 'Hello', 'dry_run' => true])
->assertOk()
->assertSee('Dry run');