Files
appwrite/tests/unit/Utopia/Messaging/Adapter/CapturingWebhook.php
Jake BarnbyandClaude Opus 4.7 ac87c0e2d6 test(notifications): add regression and happy-path coverage for review-fix critical gaps
Locks the bug-fix invariants from PR #12195's last review pass and rounds out
worker channel coverage:

C1 testEmailSendFailureDoesNotPersistAlert — SMTP throw must NOT leave a dedup
   row behind, retry must deliver and persist exactly once.
C2 testNotificationEventResetClearsAllState — reset() drops every state-bearing
   field including preview (regression: missed in original reset body).
C3 testWebhookSendAlertResetsBetweenCalls — Webhooks::sendAlert must reset()
   the DI-shared Notification event so two paused-webhook alerts in one worker
   pass do not bleed recipients/subject/body into each other.
C4 testConsoleAdapterTreatsDuplicateAsDelivered — Duplicate on createDocument
   must surface as a successful idempotent send, not a per-recipient error.
M7 testTrackingPixelRejectsJwtWithoutPurposeClaim — Track endpoint silently
   ignores JWTs missing or with the wrong purpose claim (defends against
   replaying session/reset JWTs to mark alerts read).

Worker happy-path tests: testEmailChannelHappyPath, testConsoleChannelHappyPath,
testWebhookChannelHappyPath cover the full per-channel dispatch contract end
to end, including HMAC signing for webhooks and the tracking pixel injection
+ post-send persistence for email.

Also extracts CapturingWebhook into its own PSR-4 file so reused across tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:02:12 +12:00

35 lines
1.1 KiB
PHP

<?php
namespace Tests\Unit\Utopia\Messaging\Adapter;
use Appwrite\Utopia\Messaging\Adapter\Webhook;
/**
* Test double that captures the curl request the adapter would issue and
* returns a scripted response, so callers exercise the real signing/header
* logic without touching the network. Lives in its own file so PSR-4
* autoload resolves it from any test file.
*/
class CapturingWebhook extends Webhook
{
/**
* @var array<int, array{method: string, url: string, headers: array<int, string>, body: string, timeout: int}>
*/
public array $captured = [];
/** @var array{statusCode: int, response: string|null, error: string|null} */
public array $response = ['statusCode' => 200, 'response' => 'OK', 'error' => null];
protected function dispatch(string $method, string $url, array $headers, string $body, int $timeout): array
{
$this->captured[] = [
'method' => $method,
'url' => $url,
'headers' => $headers,
'body' => $body,
'timeout' => $timeout,
];
return $this->response;
}
}