File: /home/xedaptot/be.naniguide.com/tests/Feature/SendingServerWebhooks/RecordComplaintListenerTest.php
<?php
use App\Listeners\SendingServerWebhooks\RecordComplaint;
use App\Model\Blacklist;
use App\Model\Contact;
use App\Model\Customer;
use App\Model\FeedbackLog;
use App\Model\MailList;
use App\Model\SendingServer;
use App\Model\Subscriber;
use App\Model\TrackingLog;
use App\SendingServers\Webhooks\ComplaintReceived;
use App\SendingServers\Webhooks\FeedbackType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
uses(TestCase::class, DatabaseTransactions::class);
function makeComplaintFixture(): array
{
$contact = Contact::factory()->create();
$customer = Customer::factory()->create([
'contact_id' => $contact->id,
'uid' => 'rclstcust' . uniqid(),
]);
$list = MailList::forceCreate([
'uid' => 'rclst_' . uniqid(),
'customer_id' => $customer->id,
'name' => 'fixture',
'from_name' => 'Fixture',
'from_email' => '[email protected]',
]);
$subscriber = Subscriber::factory()->create([
'mail_list_id' => $list->id,
'email' => '[email protected]',
]);
$msgId = 'cpl' . uniqid() . '.' . $customer->uid . '@example.com';
$server = SendingServer::factory()->create();
$trackingLog = TrackingLog::forceCreate([
'runtime_message_id' => $msgId,
'message_id' => 'vendor-msg-id-cpl',
'customer_id' => $customer->id,
'subscriber_id' => $subscriber->id,
'sending_server_id' => $server->id,
'status' => 'sent',
]);
return compact('customer', 'subscriber', 'msgId', 'trackingLog', 'server');
}
test('ComplaintReceived → FeedbackLog row + markAsSpamReported on subscriber (SendGrid parity)', function () {
$f = makeComplaintFixture();
$event = new ComplaintReceived(
runtimeMessageId: $f['msgId'],
type: FeedbackType::SPAM,
feedbackTypeRaw: 'spam',
shouldBlacklist: false, // SendGrid: no blacklist
shouldMarkSpamReported: true,
rawForDb: '{"raw":"sg-payload"}',
rawPayload: [],
server: $f['server'],
);
(new RecordComplaint())->handle($event);
$log = FeedbackLog::where('runtime_message_id', $f['msgId'])->firstOrFail();
expect($log->feedback_type)->toBe('spam')
->and($log->raw_feedback_content)->toBe('{"raw":"sg-payload"}')
->and($log->tracking_log_id)->toBe($f['trackingLog']->id)
->and($log->message_id)->toBe('vendor-msg-id-cpl');
expect(Blacklist::where('email', $f['subscriber']->email)->exists())->toBeFalse();
});
test('ComplaintReceived with shouldBlacklist=true → blacklist + markAsSpamReported (Mailgun Q7 parity)', function () {
$f = makeComplaintFixture();
$event = new ComplaintReceived(
runtimeMessageId: $f['msgId'],
type: FeedbackType::SPAM,
feedbackTypeRaw: 'spam',
shouldBlacklist: true, // Q7: Mailgun unique
shouldMarkSpamReported: false, // PARITY: Mailgun did NOT call markAsSpamReported
rawForDb: '{"raw":"mg-payload"}',
rawPayload: [],
server: $f['server'],
messageIdAlwaysRuntime: true, // Mailgun parity
);
(new RecordComplaint())->handle($event);
$log = FeedbackLog::where('runtime_message_id', $f['msgId'])->firstOrFail();
expect($log->message_id)->toBe($f['msgId']); // Mailgun-only override
expect(Blacklist::where('email', $f['subscriber']->email)->exists())->toBeTrue();
});
test('ComplaintReceived preserves raw feedbackTypeRaw (AWS abuse vs spam)', function () {
$f = makeComplaintFixture();
$event = new ComplaintReceived(
runtimeMessageId: $f['msgId'],
type: FeedbackType::SPAM,
feedbackTypeRaw: 'abuse', // PARITY: AWS sends 'abuse' verbatim
shouldBlacklist: false,
shouldMarkSpamReported: true,
rawForDb: '{"sns":"payload"}',
rawPayload: [],
server: $f['server'],
);
(new RecordComplaint())->handle($event);
$log = FeedbackLog::where('runtime_message_id', $f['msgId'])->firstOrFail();
expect($log->feedback_type)->toBe('abuse');
});
test('ComplaintReceived for unknown customer → log + skip (no DB write)', function () {
$server = SendingServer::factory()->create();
$event = new ComplaintReceived(
runtimeMessageId: '[email protected]',
type: FeedbackType::SPAM,
feedbackTypeRaw: 'spam',
shouldBlacklist: true,
shouldMarkSpamReported: true,
rawForDb: '{}',
rawPayload: [],
server: $server,
);
(new RecordComplaint())->handle($event);
expect(FeedbackLog::where('runtime_message_id', '[email protected]')->exists())
->toBeFalse();
});