Skip to content

Commit 7059244

Browse files
committed
test(client): cover typed exception behavior on gateway error responses
Signed-off-by: Vitor Mattos <vitor@php.rio>
1 parent c9a1cc0 commit 7059244

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

tests/Unit/Http/NfseClientTest.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
use donatj\MockWebServer\Response;
1212
use LibreCodeCoop\NfsePHP\Contracts\XmlSignerInterface;
1313
use LibreCodeCoop\NfsePHP\Dto\DpsData;
14+
use LibreCodeCoop\NfsePHP\Exception\CancellationException;
15+
use LibreCodeCoop\NfsePHP\Exception\IssuanceException;
16+
use LibreCodeCoop\NfsePHP\Exception\NfseErrorCode;
17+
use LibreCodeCoop\NfsePHP\Exception\QueryException;
1418
use LibreCodeCoop\NfsePHP\Http\NfseClient;
1519
use LibreCodeCoop\NfsePHP\SecretStore\NoOpSecretStore;
1620
use LibreCodeCoop\NfsePHP\Tests\TestCase;
@@ -117,6 +121,128 @@ public function testCancelReturnsTrueOnSuccess(): void
117121
self::assertTrue($client->cancel('abc-123', 'Cancelamento a pedido do tomador'));
118122
}
119123

124+
// -------------------------------------------------------------------------
125+
// Typed exception tests
126+
// -------------------------------------------------------------------------
127+
128+
public function testEmitThrowsIssuanceExceptionWhenGatewayRejects(): void
129+
{
130+
$payload = json_encode(['codigo' => 'E422', 'mensagem' => 'CNPJ inválido'], JSON_THROW_ON_ERROR);
131+
132+
self::$server->setResponseOfPath(
133+
'/NFS-e/api/v1/dps',
134+
new Response($payload, ['Content-Type' => 'application/json'], 422),
135+
);
136+
137+
$client = new NfseClient(
138+
secretStore: new NoOpSecretStore(),
139+
baseUrlOverride: self::$server->getServerRoot() . '/NFS-e/api/v1',
140+
signer: $this->signer,
141+
);
142+
143+
$this->expectException(IssuanceException::class);
144+
$client->emit($this->makeDps());
145+
}
146+
147+
public function testIssuanceExceptionCarriesErrorCodeHttpStatusAndUpstreamPayload(): void
148+
{
149+
$errorData = ['codigo' => 'E422', 'mensagem' => 'CNPJ inválido'];
150+
151+
self::$server->setResponseOfPath(
152+
'/NFS-e/api/v1/dps',
153+
new Response(json_encode($errorData, JSON_THROW_ON_ERROR), ['Content-Type' => 'application/json'], 422),
154+
);
155+
156+
$client = new NfseClient(
157+
secretStore: new NoOpSecretStore(),
158+
baseUrlOverride: self::$server->getServerRoot() . '/NFS-e/api/v1',
159+
signer: $this->signer,
160+
);
161+
162+
try {
163+
$client->emit($this->makeDps());
164+
self::fail('Expected IssuanceException');
165+
} catch (IssuanceException $e) {
166+
self::assertSame(NfseErrorCode::IssuanceRejected, $e->errorCode);
167+
self::assertSame(422, $e->httpStatus);
168+
self::assertSame($errorData, $e->upstreamPayload);
169+
}
170+
}
171+
172+
public function testQueryThrowsQueryExceptionWhenGatewayReturnsError(): void
173+
{
174+
self::$server->setResponseOfPath(
175+
'/NFS-e/api/v1/dps/missing-key',
176+
new Response('{"error":"not found"}', ['Content-Type' => 'application/json'], 404),
177+
);
178+
179+
$client = new NfseClient(
180+
secretStore: new NoOpSecretStore(),
181+
baseUrlOverride: self::$server->getServerRoot() . '/NFS-e/api/v1',
182+
);
183+
184+
$this->expectException(QueryException::class);
185+
$client->query('missing-key');
186+
}
187+
188+
public function testQueryExceptionCarriesErrorCodeAndHttpStatus(): void
189+
{
190+
self::$server->setResponseOfPath(
191+
'/NFS-e/api/v1/dps/missing-key',
192+
new Response('{"error":"not found"}', ['Content-Type' => 'application/json'], 404),
193+
);
194+
195+
$client = new NfseClient(
196+
secretStore: new NoOpSecretStore(),
197+
baseUrlOverride: self::$server->getServerRoot() . '/NFS-e/api/v1',
198+
);
199+
200+
try {
201+
$client->query('missing-key');
202+
self::fail('Expected QueryException');
203+
} catch (QueryException $e) {
204+
self::assertSame(NfseErrorCode::QueryFailed, $e->errorCode);
205+
self::assertSame(404, $e->httpStatus);
206+
}
207+
}
208+
209+
public function testCancelThrowsCancellationExceptionWhenGatewayReturnsError(): void
210+
{
211+
self::$server->setResponseOfPath(
212+
'/NFS-e/api/v1/dps/blocked-key',
213+
new Response('{"error":"cannot cancel"}', ['Content-Type' => 'application/json'], 409),
214+
);
215+
216+
$client = new NfseClient(
217+
secretStore: new NoOpSecretStore(),
218+
baseUrlOverride: self::$server->getServerRoot() . '/NFS-e/api/v1',
219+
);
220+
221+
$this->expectException(CancellationException::class);
222+
$client->cancel('blocked-key', 'a pedido do tomador');
223+
}
224+
225+
public function testCancellationExceptionCarriesErrorCodeAndHttpStatus(): void
226+
{
227+
self::$server->setResponseOfPath(
228+
'/NFS-e/api/v1/dps/blocked-key',
229+
new Response('{"error":"cannot cancel"}', ['Content-Type' => 'application/json'], 409),
230+
);
231+
232+
$client = new NfseClient(
233+
secretStore: new NoOpSecretStore(),
234+
baseUrlOverride: self::$server->getServerRoot() . '/NFS-e/api/v1',
235+
);
236+
237+
try {
238+
$client->cancel('blocked-key', 'a pedido do tomador');
239+
self::fail('Expected CancellationException');
240+
} catch (CancellationException $e) {
241+
self::assertSame(NfseErrorCode::CancellationRejected, $e->errorCode);
242+
self::assertSame(409, $e->httpStatus);
243+
}
244+
}
245+
120246
// -------------------------------------------------------------------------
121247

122248
private function makeDps(): DpsData

0 commit comments

Comments
 (0)