File: /home/xedaptot/ai.naniguide.com/tests/Unit/SendingServers/Webhooks/ElasticEmailParseWebhookTest.php
<?php
use App\Model\BounceLog;
use App\Model\SendingServer;
use App\SendingServers\Drivers\Vendors\ElasticEmail\ElasticEmailApiDriver;
use App\SendingServers\Webhooks\BounceReceived;
use App\SendingServers\Webhooks\BounceType;
use App\SendingServers\Webhooks\ComplaintReceived;
use App\SendingServers\Webhooks\FeedbackType;
use App\SendingServers\Webhooks\IgnorableWebhookEvent;
use Illuminate\Http\Request;
use Tests\TestCase;
uses(TestCase::class);
/**
* Wave D.2 parity test: ElasticEmail uses GET-based callbacks with
* `transaction` and `status` query params (different transport from
* other vendors which use JSON POST).
*
* Parity contract:
* - status='Error' → BounceLog HARD blacklist
* - status='AbuseReport' → FeedbackLog spam markSpamReported
* - case-insensitive comparison (legacy used strcasecmp)
* - missing transaction → log + skip
* - rawForDb := json_encode(params)
*/
function makeElasticEmailDriver(): ElasticEmailApiDriver
{
$server = new SendingServer(['type' => 'elasticemail-api', 'name' => 'fixture']);
$server->uid = 'fixture-uid';
return new ElasticEmailApiDriver($server);
}
test('elasticemail status=Error → BounceReceived (HARD, blacklist)', function () {
$driver = makeElasticEmailDriver();
$req = Request::create('/webhook/elasticemail-api/fixture-uid?transaction=fixture-tx-001&status=Error&[email protected]', 'GET');
$events = iterator_to_array($driver->parseWebhook($req));
expect($events)->toHaveCount(1)
->and($events[0])->toBeInstanceOf(BounceReceived::class)
->and($events[0]->runtimeMessageId)->toBe('fixture-tx-001')
->and($events[0]->type)->toBe(BounceType::HARD)
->and($events[0]->bounceTypeRaw)->toBe(BounceLog::HARD)
->and($events[0]->shouldBlacklist)->toBeTrue();
});
test('elasticemail status=AbuseReport → ComplaintReceived (markSpamReported, no blacklist)', function () {
$driver = makeElasticEmailDriver();
$req = Request::create('/webhook/elasticemail-api/fixture-uid?transaction=fixture-tx-002&status=AbuseReport', 'GET');
$events = iterator_to_array($driver->parseWebhook($req));
expect($events)->toHaveCount(1)
->and($events[0])->toBeInstanceOf(ComplaintReceived::class)
->and($events[0]->type)->toBe(FeedbackType::SPAM)
->and($events[0]->feedbackTypeRaw)->toBe('spam')
->and($events[0]->shouldBlacklist)->toBeFalse()
->and($events[0]->shouldMarkSpamReported)->toBeTrue();
});
test('elasticemail case-insensitive status (legacy used strcasecmp)', function () {
$driver = makeElasticEmailDriver();
$req = Request::create('/webhook/elasticemail-api/fixture-uid?transaction=tx&status=ERROR', 'GET');
$events = iterator_to_array($driver->parseWebhook($req));
expect($events[0])->toBeInstanceOf(BounceReceived::class);
});
test('elasticemail unknown status → IgnorableWebhookEvent (parity skip)', function () {
$driver = makeElasticEmailDriver();
$req = Request::create('/webhook/elasticemail-api/fixture-uid?transaction=tx&status=Sent', 'GET');
$events = iterator_to_array($driver->parseWebhook($req));
expect($events)->toHaveCount(1)
->and($events[0])->toBeInstanceOf(IgnorableWebhookEvent::class);
});
test('elasticemail missing transaction → no events', function () {
$driver = makeElasticEmailDriver();
$req = Request::create('/webhook/elasticemail-api/fixture-uid?status=Error', 'GET');
$events = iterator_to_array($driver->parseWebhook($req));
expect($events)->toBeEmpty();
});
test('elasticemail rawForDb is json_encode of full param array (parity)', function () {
$driver = makeElasticEmailDriver();
$req = Request::create('/webhook/elasticemail-api/fixture-uid?transaction=tx-1&status=Error&extra=x', 'GET');
$events = iterator_to_array($driver->parseWebhook($req));
$expected = json_encode(['transaction' => 'tx-1', 'status' => 'Error', 'extra' => 'x']);
expect($events[0]->rawForDb)->toBe($expected);
});