Closes the last coverage gap for org (person remains intentionally unaddressed — no good free/non-scraping option exists). Unlike the other 8 sources, OpenCorporates now requires an API token even on its free tier (confirmed: keyless request gets 401). RunnerRegistry::has() checks services.opencorporates.token is configured before exposing the source as runnable, so it degrades to "not yet integrated" in the UI rather than a broken Run button, until OPENCORPORATES_API_TOKEN is set. Also fixes a real bug hit while building this: a RunnerRegistry::REQUIRES class constant mapping source key to a closure crashed on file load (PHP class constants can't hold closures) — inlined the one check instead of building an abstraction for a single case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
96 lines
3.1 KiB
PHP
96 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Osint;
|
|
|
|
use App\Models\Target;
|
|
use App\Osint\Runners\OpenCorporatesRunner;
|
|
use App\Osint\RunnerException;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Tests\TestCase;
|
|
|
|
class OpenCorporatesRunnerTest extends TestCase
|
|
{
|
|
public function test_throws_when_no_token_configured(): void
|
|
{
|
|
config(['services.opencorporates.token' => null]);
|
|
|
|
$target = new Target(['type' => 'org', 'value' => 'Acme Inc']);
|
|
|
|
$this->expectException(RunnerException::class);
|
|
$this->expectExceptionMessage('API token not configured');
|
|
|
|
(new OpenCorporatesRunner)->run($target);
|
|
}
|
|
|
|
public function test_parses_search_results_into_matches(): void
|
|
{
|
|
config(['services.opencorporates.token' => 'test-token']);
|
|
|
|
Http::fake([
|
|
'api.opencorporates.com/*' => Http::response([
|
|
'results' => [
|
|
'companies' => [
|
|
[
|
|
'company' => [
|
|
'name' => 'Acme Inc',
|
|
'jurisdiction_code' => 'us_de',
|
|
'current_status' => 'Active',
|
|
'opencorporates_url' => 'https://opencorporates.com/companies/us_de/123',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
]),
|
|
]);
|
|
|
|
$target = new Target(['type' => 'org', 'value' => 'Acme Inc']);
|
|
|
|
$result = (new OpenCorporatesRunner)->run($target);
|
|
|
|
$this->assertCount(1, $result->raw['matches']);
|
|
$this->assertSame('Acme Inc (us_de, Active)', $result->raw['matches'][0]['name']);
|
|
$this->assertSame('https://opencorporates.com/companies/us_de/123', $result->raw['matches'][0]['url']);
|
|
$this->assertStringContainsString('Found 1 company', $result->summary);
|
|
}
|
|
|
|
public function test_reports_no_companies_found(): void
|
|
{
|
|
config(['services.opencorporates.token' => 'test-token']);
|
|
|
|
Http::fake([
|
|
'api.opencorporates.com/*' => Http::response(['results' => ['companies' => []]]),
|
|
]);
|
|
|
|
$target = new Target(['type' => 'org', 'value' => 'Nonexistent Org XYZ']);
|
|
|
|
$result = (new OpenCorporatesRunner)->run($target);
|
|
|
|
$this->assertSame([], $result->raw['matches']);
|
|
$this->assertStringContainsString('No companies found', $result->summary);
|
|
}
|
|
|
|
public function test_rejects_non_org_targets(): void
|
|
{
|
|
config(['services.opencorporates.token' => 'test-token']);
|
|
|
|
$target = new Target(['type' => 'domain', 'value' => 'example.com']);
|
|
|
|
$this->expectException(RunnerException::class);
|
|
|
|
(new OpenCorporatesRunner)->run($target);
|
|
}
|
|
|
|
public function test_throws_on_http_failure(): void
|
|
{
|
|
config(['services.opencorporates.token' => 'test-token']);
|
|
|
|
Http::fake(['api.opencorporates.com/*' => Http::response('', 401)]);
|
|
|
|
$target = new Target(['type' => 'org', 'value' => 'Acme Inc']);
|
|
|
|
$this->expectException(RunnerException::class);
|
|
|
|
(new OpenCorporatesRunner)->run($target);
|
|
}
|
|
}
|