paid_ads-8.x-1.x-dev/tests/src/Unit/PaypalGatewayTest.php
tests/src/Unit/PaypalGatewayTest.php
<?php
namespace Drupal\Tests\paid_ads\Unit;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Logger\LoggerChannel;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\paid_ads\Entity\PaidPaymentInterface;
use Drupal\paid_ads\Plugin\PaidGateways\PaypalGateway;
use Drupal\Tests\UnitTestCase;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\MockObject\Stub;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
/**
* Class PaypalGatewayTest.
*
* @group paid_ads
*/
class PaypalGatewayTest extends UnitTestCase {
/**
* Logger mock.
*
* @var \Psr\Log\LoggerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $logger;
/**
* Http Client mock.
*
* @var \GuzzleHttp\ClientInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $httpClient;
/**
* Drupal entity type manager mock.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $entityTypeManager;
/**
* Debug flag.
*
* @var bool
*/
protected $debug = FALSE;
/**
* Module configuration.
*
* @var array
*/
private $config = [
'paid_ads.gateways' => [
'paid_ads' => [
'gateways' => [
'plugin_id' => [
'mode' => 'https://api.sandbox.paypal.com',
'client_id' => 'sometext',
'secret_id' => 'someothertext',
],
],
],
],
];
private $storages = [];
/**
* Mocks storages and methods for entity type manager.
*
* @param string $storage
* Storage name.
* @param array $methods
* Methods to mock.
*
* @return \PHPUnit\Framework\MockObject\MockObject
* Storage mock.
*/
private function mockStorage($storage, array $methods) {
if (!isset($this->storages[$storage])) {
$this->storages[$storage]['mock'] = $this->getMockBuilder(
EntityStorageInterface::class
)
->disableOriginalConstructor()
->getMock();
$this->storages[$storage]['methods'] = [];
}
foreach ($methods as $name => $data) {
if (!isset($this->storages[$storage]['methods'][$name])) {
$this->storages[$storage]['methods'][$name] = $this->storages[$storage]['mock']->method(
$name
);
}
/** @var \PHPUnit\Framework\MockObject\Builder\InvocationMocker $method */
$method = $this->storages[$storage]['methods'][$name];
if (is_callable($data)) {
$method->willReturnCallback($data);
}
elseif (is_array($data)) {
$method->willReturnMap($data);
}
elseif ($data instanceof Stub) {
$method->will($data);
}
else {
$method->willReturn($data);
}
}
return $this->storages[$storage]['mock'];
}
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$channel = $this->getMockBuilder(LoggerChannel::class)
->setConstructorArgs(['some'])
->setMethods(['log'])
->getMock();
$channel->method('log')
->willReturnCallback(
function ($level, $message, array $context = []) {
if ($this->debug) {
fwrite(STDOUT, $message . PHP_EOL);
}
}
);
$this->logger = $this->createConfiguredMock(
LoggerChannelFactory::class,
[
'get' => $channel,
]
);
$this->entityTypeManager = $this->getMockBuilder(
EntityTypeManagerInterface::class
)
->disableOriginalConstructor()
->getMock();
$this->entityTypeManager->method('getStorage')
->willReturnCallback(
function ($name) {
if (isset($this->storages[$name])) {
return $this->storages[$name]['mock'];
}
else {
throw new InvalidPluginDefinitionException($name);
}
}
);
$this->httpClient = $this->createPartialMock(Client::class, ['request']);
}
/**
* Creates a new testing object.
*
* @return \Drupal\paid_ads\Plugin\PaidGateways\PaypalGateway
* New instance.
*/
protected function getInstance($methods = NULL) {
$mock = $this->getMockBuilder(PaypalGateway::class)
->setConstructorArgs(
[
[],
'plugin_id',
[],
$this->getConfigFactoryStub($this->config),
$this->logger,
$this->entityTypeManager,
$this->httpClient,
]
)
->setMethods($methods)
->getMock();
$mock->setStringTranslation($this->getStringTranslationStub());
return $mock;
}
/**
* Tests if the configuration is read properly.
*/
public function testConfiguration() {
$instance = $this->getInstance();
$options = $this->config['paid_ads.gateways']['paid_ads']['gateways']['plugin_id'];
self::assertEquals($options, $instance->getOptions());
$form = $instance->buildConfigurationForm([], new FormState());
self::assertEquals(
$options['client_id'],
$form['client_id']['#default_value']
);
self::assertEquals(
$options['secret_id'],
$form['secret_id']['#default_value']
);
self::assertEquals($options['mode'], $form['mode']['#default_value']);
}
/**
* Tests if create order event handler calls to PayPal.
*/
public function testPayPalApiCalledOnCreateOrder() {
$config = &$this->config['paid_ads.gateways']['paid_ads']['gateways']['plugin_id'];
$config['mode'] = $this->randomMachineName(16);
$currency = $this->randomMachineName(3);
$amount = random_int(1, 500);
$payment = $this->getMockBuilder(PaidPaymentInterface::class)
->getMock();
$payment->expects(self::atLeastOnce())
->method('setOrderId')
->with("someid");
$payment->expects(self::atLeastOnce())
->method('getAmount')
->willReturn($amount);
$payment->expects(self::atLeastOnce())
->method('getCurrency')
->willReturn($currency);
$instance = $this->getInstance();
$this->httpClient->expects(self::atLeastOnce())
->method('request')
->willReturnCallback(
function ($method, $uri, array $options = []) use ($config, $amount, $currency) {
self::assertEquals('post', $method);
self::assertEquals($config['mode'] . '/v2/checkout/orders', $uri);
self::assertEquals(
[$config['client_id'], $config['secret_id']],
$options['auth']
);
self::assertEquals(
$amount,
$options['json']['purchase_units'][0]['amount']['value']
);
self::assertEquals(
$currency,
$options['json']['purchase_units'][0]['amount']['currency_code']
);
return new Response(200, [], '{"id":"someid"}');
}
);
$result = $instance->onCreatePayment(['payment' => $payment]);
self::assertInstanceOf(JsonResponse::class, $result);
self::assertEquals(200, $result->getStatusCode());
}
/**
* Tests if exceptions are handled in create order request handler.
*/
public function testOnCreateOrderHandlesExceptions() {
$instance = $this->getInstance();
$payment = $this->getMockBuilder(PaidPaymentInterface::class)
->getMock();
$this->httpClient->expects(self::atLeastOnce())
->method('request')
->willThrowException(new Exception());
$result = $instance->onCreatePayment(['payment' => $payment]);
self::assertInstanceOf(JsonResponse::class, $result);
self::assertEquals(500, $result->getStatusCode());
}
/**
* Tests approve order event handler.
*/
public function testPayPalApiCalledOnApprove() {
$config = &$this->config['paid_ads.gateways']['paid_ads']['gateways']['plugin_id'];
$config['mode'] = $this->randomMachineName(16);
$paymentId = $this->randomMachineName();
$payerId = $this->randomMachineName();
// Fake request data.
$request = $this->getMockBuilder(Request::class)
->setMethods(['get'])
->getMock();
$request->method('get')
->willReturnMap(
[
['paymentID', NULL, $paymentId],
['payerID', NULL, $payerId],
]
);
$paymentEntity = $this->getMockBuilder(PaidPaymentInterface::class)
->getMock();
$paymentEntity->expects(self::any())
->method('execute');
// "Add" entity with given id to the storage.
$this->mockStorage(
'paid_payment',
[
'loadByProperties' => [
[['order_id' => $paymentId], [$paymentEntity]],
],
]
);
$this->httpClient->expects(self::atLeastOnce())
->method('request')
->willReturnCallback(
// Check API call params.
function ($method, $uri, $options) use ($config, $paymentId) {
self::assertArraySubset(
[
'auth' => [$config['client_id'], $config['secret_id']],
'headers' => ['Content-Type' => 'application/json'],
],
$options
);
self::assertEquals('get', $method);
self::assertEquals(
$config['mode'] . '/v2/checkout/orders/' . $paymentId,
$uri
);
// Return successfull response.
return new Response(
200,
[],
'{ "status": "COMPLETED","id":"' . $paymentId . '"}'
);
}
);
$instance = $this->getInstance();
$result = $instance->onApprovePayment(['request' => $request]);
self::assertInstanceOf(JsonResponse::class, $result);
self::assertEquals(200, $result->getStatusCode());
}
/**
* Tests if exceptions are handled correctly on approving an order.
*/
public function testOnApproveOrderHandlesExceptions() {
$instance = $this->getInstance();
$paymentId = $this->randomMachineName();
$payerId = $this->randomMachineName();
$request = $this->getMockBuilder(Request::class)
->getMock();
$request->method('get')
->willReturnMap(['paymentID', $paymentId, 'payerID', $payerId]);
$this->httpClient->expects(self::atLeastOnce())
->method('request')
->willThrowException(new Exception());
$result = $instance->onApprovePayment(['request' => $request]);
self::assertInstanceOf(JsonResponse::class, $result);
self::assertEquals(500, $result->getStatusCode());
}
}
