Skip to content

Commit 151a2ff

Browse files
committed
Add unit tests
1 parent bade6ad commit 151a2ff

4 files changed

Lines changed: 360 additions & 0 deletions

File tree

tests/PHPUnit/ApiClient/Endpoint/OrderEndpointTest.php

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use WooCommerce\PayPalCommerce\ApiClient\Entity\Address;
1010
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
1111
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
12+
use WooCommerce\PayPalCommerce\ApiClient\Entity\FraudProcessorResponse;
1213
use WooCommerce\PayPalCommerce\ApiClient\Entity\ExperienceContext;
1314
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
1415
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
@@ -1202,5 +1203,187 @@ function ($url, $args) use ($rawResponse, $host) {
12021203
$payer->expects('to_array')->andReturn(['payer']);
12031204
$testee->create([$purchaseUnit], ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $payer);
12041205
}
1206+
1207+
public function testCaptureDeclinedWithFraudResponseCodeThrowsDetailedMessage(): void
1208+
{
1209+
expect('wp_json_encode')->andReturnUsing('json_encode');
1210+
$orderId = 'id';
1211+
$orderToCaptureStatus = Mockery::mock(OrderStatus::class);
1212+
$orderToCaptureStatus->expects('is')->with('COMPLETED')->andReturn(false);
1213+
$orderToCapture = Mockery::mock(Order::class);
1214+
$orderToCapture->expects('status')->andReturn($orderToCaptureStatus);
1215+
$orderToCapture->expects('id')->andReturn($orderId);
1216+
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
1217+
$headers->shouldReceive('getAll');
1218+
$rawResponse = [
1219+
'body' => '{"id":"order123"}',
1220+
'headers' => $headers,
1221+
];
1222+
$expectedOrder = Mockery::mock(Order::class);
1223+
$host = 'https://example.com/';
1224+
$token = Mockery::mock(Token::class);
1225+
$token->expects('token')->andReturn('bearer');
1226+
$bearer = Mockery::mock(Bearer::class);
1227+
$bearer->expects('bearer')->andReturn($token);
1228+
$orderFactory = Mockery::mock(OrderFactory::class);
1229+
$orderFactory->expects('from_paypal_response')->andReturn($expectedOrder);
1230+
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
1231+
$logger = Mockery::mock(LoggerInterface::class);
1232+
$logger->shouldNotReceive('warning');
1233+
$logger->shouldReceive('debug');
1234+
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
1235+
$fraudnet = Mockery::mock(FraudNet::class);
1236+
1237+
$testee = new OrderEndpoint(
1238+
$host,
1239+
$bearer,
1240+
$orderFactory,
1241+
$patchCollectionFactory,
1242+
'CAPTURE',
1243+
$logger,
1244+
$subscription_helper,
1245+
false,
1246+
$fraudnet
1247+
);
1248+
1249+
expect('wp_remote_get')->andReturn($rawResponse);
1250+
expect('is_wp_error')->with($rawResponse)->andReturn(false);
1251+
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(201);
1252+
1253+
$fraud = new FraudProcessorResponse(null, null, '9500');
1254+
$purchaseUnit = Mockery::mock(PurchaseUnit::class);
1255+
$payment = Mockery::mock(Payments::class);
1256+
$capture = Mockery::mock(Capture::class);
1257+
$expectedOrder->shouldReceive('purchase_units')->once()->andReturn([$purchaseUnit]);
1258+
$purchaseUnit->shouldReceive('payments')->once()->andReturn($payment);
1259+
$payment->shouldReceive('captures')->once()->andReturn([$capture]);
1260+
$capture->shouldReceive('status')->once()->andReturn(new CaptureStatus(CaptureStatus::DECLINED));
1261+
$capture->shouldReceive('fraud_processor_response')->once()->andReturn($fraud);
1262+
1263+
$this->expectException(RuntimeException::class);
1264+
$this->expectExceptionMessageMatches('/9500: Suspected Fraud/');
1265+
$testee->capture($orderToCapture);
1266+
}
1267+
1268+
public function testCaptureDeclinedWithNullFraudThrowsGenericMessage(): void
1269+
{
1270+
expect('wp_json_encode')->andReturnUsing('json_encode');
1271+
$orderId = 'id';
1272+
$orderToCaptureStatus = Mockery::mock(OrderStatus::class);
1273+
$orderToCaptureStatus->expects('is')->with('COMPLETED')->andReturn(false);
1274+
$orderToCapture = Mockery::mock(Order::class);
1275+
$orderToCapture->expects('status')->andReturn($orderToCaptureStatus);
1276+
$orderToCapture->expects('id')->andReturn($orderId);
1277+
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
1278+
$headers->shouldReceive('getAll');
1279+
$rawResponse = [
1280+
'body' => '{"id":"order123"}',
1281+
'headers' => $headers,
1282+
];
1283+
$expectedOrder = Mockery::mock(Order::class);
1284+
$host = 'https://example.com/';
1285+
$token = Mockery::mock(Token::class);
1286+
$token->expects('token')->andReturn('bearer');
1287+
$bearer = Mockery::mock(Bearer::class);
1288+
$bearer->expects('bearer')->andReturn($token);
1289+
$orderFactory = Mockery::mock(OrderFactory::class);
1290+
$orderFactory->expects('from_paypal_response')->andReturn($expectedOrder);
1291+
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
1292+
$logger = Mockery::mock(LoggerInterface::class);
1293+
$logger->shouldNotReceive('warning');
1294+
$logger->shouldReceive('debug');
1295+
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
1296+
$fraudnet = Mockery::mock(FraudNet::class);
1297+
1298+
$testee = new OrderEndpoint(
1299+
$host,
1300+
$bearer,
1301+
$orderFactory,
1302+
$patchCollectionFactory,
1303+
'CAPTURE',
1304+
$logger,
1305+
$subscription_helper,
1306+
false,
1307+
$fraudnet
1308+
);
1309+
1310+
expect('wp_remote_get')->andReturn($rawResponse);
1311+
expect('is_wp_error')->with($rawResponse)->andReturn(false);
1312+
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(201);
1313+
1314+
$purchaseUnit = Mockery::mock(PurchaseUnit::class);
1315+
$payment = Mockery::mock(Payments::class);
1316+
$capture = Mockery::mock(Capture::class);
1317+
$expectedOrder->shouldReceive('purchase_units')->once()->andReturn([$purchaseUnit]);
1318+
$purchaseUnit->shouldReceive('payments')->once()->andReturn($payment);
1319+
$payment->shouldReceive('captures')->once()->andReturn([$capture]);
1320+
$capture->shouldReceive('status')->once()->andReturn(new CaptureStatus(CaptureStatus::DECLINED));
1321+
$capture->shouldReceive('fraud_processor_response')->once()->andReturn(null);
1322+
1323+
$this->expectException(RuntimeException::class);
1324+
$this->expectExceptionMessage('Payment provider declined the payment, please use a different payment method.');
1325+
$testee->capture($orderToCapture);
1326+
}
1327+
1328+
public function testCaptureDeclinedWithEmptyResponseCodeThrowsGenericMessage(): void
1329+
{
1330+
expect('wp_json_encode')->andReturnUsing('json_encode');
1331+
$orderId = 'id';
1332+
$orderToCaptureStatus = Mockery::mock(OrderStatus::class);
1333+
$orderToCaptureStatus->expects('is')->with('COMPLETED')->andReturn(false);
1334+
$orderToCapture = Mockery::mock(Order::class);
1335+
$orderToCapture->expects('status')->andReturn($orderToCaptureStatus);
1336+
$orderToCapture->expects('id')->andReturn($orderId);
1337+
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
1338+
$headers->shouldReceive('getAll');
1339+
$rawResponse = [
1340+
'body' => '{"id":"order123"}',
1341+
'headers' => $headers,
1342+
];
1343+
$expectedOrder = Mockery::mock(Order::class);
1344+
$host = 'https://example.com/';
1345+
$token = Mockery::mock(Token::class);
1346+
$token->expects('token')->andReturn('bearer');
1347+
$bearer = Mockery::mock(Bearer::class);
1348+
$bearer->expects('bearer')->andReturn($token);
1349+
$orderFactory = Mockery::mock(OrderFactory::class);
1350+
$orderFactory->expects('from_paypal_response')->andReturn($expectedOrder);
1351+
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
1352+
$logger = Mockery::mock(LoggerInterface::class);
1353+
$logger->shouldNotReceive('warning');
1354+
$logger->shouldReceive('debug');
1355+
$subscription_helper = Mockery::mock(SubscriptionHelper::class);
1356+
$fraudnet = Mockery::mock(FraudNet::class);
1357+
1358+
$testee = new OrderEndpoint(
1359+
$host,
1360+
$bearer,
1361+
$orderFactory,
1362+
$patchCollectionFactory,
1363+
'CAPTURE',
1364+
$logger,
1365+
$subscription_helper,
1366+
false,
1367+
$fraudnet
1368+
);
1369+
1370+
expect('wp_remote_get')->andReturn($rawResponse);
1371+
expect('is_wp_error')->with($rawResponse)->andReturn(false);
1372+
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(201);
1373+
1374+
$fraud = new FraudProcessorResponse(null, null, null);
1375+
$purchaseUnit = Mockery::mock(PurchaseUnit::class);
1376+
$payment = Mockery::mock(Payments::class);
1377+
$capture = Mockery::mock(Capture::class);
1378+
$expectedOrder->shouldReceive('purchase_units')->once()->andReturn([$purchaseUnit]);
1379+
$purchaseUnit->shouldReceive('payments')->once()->andReturn($payment);
1380+
$payment->shouldReceive('captures')->once()->andReturn([$capture]);
1381+
$capture->shouldReceive('status')->once()->andReturn(new CaptureStatus(CaptureStatus::DECLINED));
1382+
$capture->shouldReceive('fraud_processor_response')->once()->andReturn($fraud);
1383+
1384+
$this->expectException(RuntimeException::class);
1385+
$this->expectExceptionMessage('Payment provider declined the payment, please use a different payment method.');
1386+
$testee->capture($orderToCapture);
1387+
}
12051388
}
12061389

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
6+
7+
use WooCommerce\PayPalCommerce\TestCase;
8+
9+
class FraudProcessorResponseTest extends TestCase
10+
{
11+
public function testResponseCodeGetter(): void
12+
{
13+
$testee = new FraudProcessorResponse('A', 'M', '9500');
14+
$this->assertSame('9500', $testee->response_code());
15+
}
16+
17+
public function testNullResponseCodeStoredAsEmptyString(): void
18+
{
19+
$testee = new FraudProcessorResponse('A', 'M', null);
20+
$this->assertSame('', $testee->response_code());
21+
}
22+
23+
public function testToArrayIncludesResponseCode(): void
24+
{
25+
$testee = new FraudProcessorResponse('A', 'M', '9500');
26+
$array = $testee->to_array();
27+
28+
$this->assertArrayHasKey('response_code', $array);
29+
$this->assertSame('9500', $array['response_code']);
30+
}
31+
32+
public function testToArrayWithoutResponseCodeHasEmptyString(): void
33+
{
34+
$testee = new FraudProcessorResponse('A', 'M', null);
35+
$array = $testee->to_array();
36+
37+
$this->assertArrayHasKey('response_code', $array);
38+
$this->assertSame('', $array['response_code']);
39+
}
40+
41+
public function testGetResponseCodeMessageForKnownCode9500(): void
42+
{
43+
$testee = new FraudProcessorResponse(null, null, '9500');
44+
$this->assertSame('9500: Suspected Fraud', $testee->get_response_code_message());
45+
}
46+
47+
public function testGetResponseCodeMessageForKnownCode0000(): void
48+
{
49+
$testee = new FraudProcessorResponse(null, null, '0000');
50+
$this->assertSame('0000: Approved', $testee->get_response_code_message());
51+
}
52+
53+
public function testGetResponseCodeMessageForKnownCode9100(): void
54+
{
55+
$testee = new FraudProcessorResponse(null, null, '9100');
56+
$this->assertSame('9100: Declined, Please Retry', $testee->get_response_code_message());
57+
}
58+
59+
public function testGetResponseCodeMessageForUnknownCode(): void
60+
{
61+
$testee = new FraudProcessorResponse(null, null, 'ZZZZ');
62+
$this->assertSame('ZZZZ: Unknown response code', $testee->get_response_code_message());
63+
}
64+
65+
public function testGetResponseCodeMessageForEmptyCodeReturnsEmptyString(): void
66+
{
67+
$testee = new FraudProcessorResponse(null, null, null);
68+
$this->assertSame('', $testee->get_response_code_message());
69+
}
70+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
6+
7+
use WooCommerce\PayPalCommerce\ApiClient\Entity\FraudProcessorResponse;
8+
use WooCommerce\PayPalCommerce\TestCase;
9+
10+
class FraudProcessorResponseFactoryTest extends TestCase
11+
{
12+
public function testFromPaypalResponseParsesAllFields(): void
13+
{
14+
$data = (object) [
15+
'avs_code' => 'Y',
16+
'cvv_code' => 'M',
17+
'response_code' => '9500',
18+
];
19+
20+
$testee = new FraudProcessorResponseFactory();
21+
$result = $testee->from_paypal_response($data);
22+
23+
$this->assertInstanceOf(FraudProcessorResponse::class, $result);
24+
$this->assertSame('Y', $result->avs_code());
25+
$this->assertSame('M', $result->cvv_code());
26+
$this->assertSame('9500', $result->response_code());
27+
}
28+
29+
public function testFromPaypalResponseWithMissingResponseCode(): void
30+
{
31+
$data = (object) [
32+
'avs_code' => 'Y',
33+
'cvv_code' => 'M',
34+
];
35+
36+
$testee = new FraudProcessorResponseFactory();
37+
$result = $testee->from_paypal_response($data);
38+
39+
$this->assertSame('', $result->response_code());
40+
}
41+
42+
public function testFromPaypalResponseWithEmptyResponseCode(): void
43+
{
44+
$data = (object) [
45+
'avs_code' => 'Y',
46+
'cvv_code' => 'M',
47+
'response_code' => '',
48+
];
49+
50+
$testee = new FraudProcessorResponseFactory();
51+
$result = $testee->from_paypal_response($data);
52+
53+
// Empty string is falsy; the factory coerces it to null, stored as empty string.
54+
$this->assertSame('', $result->response_code());
55+
}
56+
}

tests/PHPUnit/WcGateway/Processor/AuthorizedPaymentsProcessorTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
1616
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
1717
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
18+
use WooCommerce\PayPalCommerce\ApiClient\Entity\FraudProcessorResponse;
1819
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
1920
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
2021
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
@@ -259,6 +260,56 @@ private function createAuthorization(string $id, string $status): Authorization
259260
return new Authorization($id, new AuthorizationStatus($status), null);
260261
}
261262

263+
public function testCaptureAuthorizedPaymentDeclinedWithFraudResponseCodeAddsOrderNoteAndThrows(): void
264+
{
265+
$this->orderEndpoint->shouldReceive('order')->andReturn($this->paypalOrder);
266+
267+
$fraud = new FraudProcessorResponse(null, null, '9500');
268+
$capture = Mockery::mock(Capture::class);
269+
$capture->shouldReceive('id')->andReturn($this->captureId);
270+
$capture->shouldReceive('status')->andReturn(new CaptureStatus(CaptureStatus::DECLINED));
271+
$capture->shouldReceive('fraud_processor_response')->andReturn($fraud);
272+
273+
$this->paymentsEndpoint
274+
->expects('capture')
275+
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
276+
->andReturn($capture);
277+
278+
$this->wcOrder->shouldReceive('update_status');
279+
$this->wcOrder
280+
->shouldReceive('add_order_note')
281+
->once()
282+
->with(Mockery::on(function (string $note): bool {
283+
return strpos($note, '9500: Suspected Fraud') !== false;
284+
}));
285+
286+
$this->expectException(RuntimeException::class);
287+
$this->expectExceptionMessageMatches('/9500: Suspected Fraud/');
288+
$this->testee->capture_authorized_payment($this->wcOrder);
289+
}
290+
291+
public function testCaptureAuthorizedPaymentDeclinedWithoutFraudCodeThrowsGenericMessage(): void
292+
{
293+
$this->orderEndpoint->shouldReceive('order')->andReturn($this->paypalOrder);
294+
295+
$capture = Mockery::mock(Capture::class);
296+
$capture->shouldReceive('id')->andReturn($this->captureId);
297+
$capture->shouldReceive('status')->andReturn(new CaptureStatus(CaptureStatus::DECLINED));
298+
$capture->shouldReceive('fraud_processor_response')->andReturn(null);
299+
300+
$this->paymentsEndpoint
301+
->expects('capture')
302+
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
303+
->andReturn($capture);
304+
305+
$this->wcOrder->shouldReceive('update_status');
306+
$this->wcOrder->shouldNotReceive('add_order_note');
307+
308+
$this->expectException(RuntimeException::class);
309+
$this->expectExceptionMessage('Payment provider declined the payment, please use a different payment method.');
310+
$this->testee->capture_authorized_payment($this->wcOrder);
311+
}
312+
262313
private function createCapture(string $id, string $status): Capture {
263314
$capture = Mockery::mock(Capture::class);
264315
$capture

0 commit comments

Comments
 (0)