From 78f7c382d073c4d6f1fd6c7470d38e414106a1e4 Mon Sep 17 00:00:00 2001 From: Andre Kutianski Date: Thu, 9 Jul 2026 22:26:06 -0300 Subject: [PATCH] fix(tests): webhook integration usa o envelope v2 (data era o corpo todo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O teste `test_constructEvent_aceita_payload_assinado` montava um payload FLAT (`{type, data:{id:'inv-123'}, id:'evt-001'}`) e afirmava `data['id'] === 'inv-123'`. Mas para payload flat o `Webhook::constructEvent` (corretamente) define `data = corpo decodificado inteiro`, então `data['id']` era `'evt-001'` — o teste falhava na `integration.yml`. Semântica de "data aninhado" só existe no **envelope v2** (`{action, payload}`), que é o contrato real da API (fix-account-webhooks-contract). Correções: - O teste principal passa a usar o envelope v2 → `data` é o `payload` aninhado; as três asserções (type/id/data['id']) voltam a fazer sentido e a passar. - Novo teste pina o fallback flat (`data` = corpo inteiro) — documenta os dois caminhos do `constructEvent`. Bug era só no teste; o código de `constructEvent` está correto. Não relacionado à change expand-service-invoice-dto (constructEvent monta WebhookEvent direto, sem passar por hydrate()). --- .../WebhookSignatureIntegrationTest.php | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/Integration/WebhookSignatureIntegrationTest.php b/tests/Integration/WebhookSignatureIntegrationTest.php index f89cf68..0b82060 100644 --- a/tests/Integration/WebhookSignatureIntegrationTest.php +++ b/tests/Integration/WebhookSignatureIntegrationTest.php @@ -24,12 +24,14 @@ protected function setUp(): void $this->secret = $this->requireEnv('NFE_SDK_E2E_WEBHOOK_SECRET'); } - public function test_constructEvent_aceita_payload_assinado_corretamente(): void + public function test_constructEvent_aceita_envelope_v2_assinado_corretamente(): void { + // Envelope v2 real da NFE.io: { action, payload } — `data` é o payload + // aninhado (não o corpo inteiro). $payload = json_encode([ - 'type' => 'invoice.issued', - 'data' => ['id' => 'inv-123', 'flowStatus' => 'Issued'], - 'id' => 'evt-001', + 'action' => 'service_invoice.issued_successfully', + 'payload' => ['id' => 'inv-123', 'flowStatus' => 'Issued'], + 'id' => 'evt-001', 'createdAt' => '2026-01-01T00:00:00Z', ], JSON_THROW_ON_ERROR); @@ -37,14 +39,34 @@ public function test_constructEvent_aceita_payload_assinado_corretamente(): void $event = Webhook::constructEvent(payload: $payload, sigHeader: $sig, secret: $this->secret); - $this->assertSame('invoice.issued', $event->type); + $this->assertSame('service_invoice.issued_successfully', $event->type); $this->assertSame('evt-001', $event->id); $this->assertSame('inv-123', $event->data['id']); + $this->assertSame('Issued', $event->data['flowStatus']); + } + + public function test_constructEvent_payload_flat_usa_o_corpo_todo_como_data(): void + { + // Sem envelope v2 (`action`/`payload`), o helper cai no fallback flat: + // `data` passa a ser o corpo decodificado inteiro, e `type` vem de + // type/event_type/action. Este teste pina esse contrato. + $payload = json_encode([ + 'type' => 'service_invoice.issued_successfully', + 'id' => 'inv-999', + ], JSON_THROW_ON_ERROR); + + $sig = 'sha1=' . hash_hmac('sha1', $payload, $this->secret); + + $event = Webhook::constructEvent(payload: $payload, sigHeader: $sig, secret: $this->secret); + + $this->assertSame('service_invoice.issued_successfully', $event->type); + $this->assertSame('inv-999', $event->data['id']); // data = corpo inteiro + $this->assertSame('inv-999', $event->id); } public function test_constructEvent_recusa_assinatura_invalida(): void { - $payload = '{"type":"invoice.issued"}'; + $payload = '{"action":"service_invoice.issued_successfully","payload":{}}'; $sig = 'sha1=' . hash_hmac('sha1', $payload, 'wrong-secret'); $this->expectException(SignatureVerificationException::class);