<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Signifyd\Test\Unit\Observer; use Magento\Framework\Event; use Magento\Framework\Event\Observer; use Magento\Framework\Exception\AlreadyExistsException; use Magento\Payment\Model\MethodInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; use Magento\Signifyd\Api\CaseCreationServiceInterface; use Magento\Signifyd\Model\Config; use Magento\Signifyd\Observer\PlaceOrder; use PHPUnit_Framework_MockObject_MockObject as MockObject; use Psr\Log\LoggerInterface; class PlaceOrderTest extends \PHPUnit\Framework\TestCase { /** * @var Config|MockObject */ private $config; /** * @var CaseCreationServiceInterface|MockObject */ private $creationService; /** * @var LoggerInterface|MockObject */ private $logger; /** * @var Observer|MockObject */ private $observer; /** * @var Event|MockObject */ private $event; /** * @var OrderInterface|MockObject */ private $orderEntity; /** * @var PlaceOrder */ private $placeOrder; /** * @inheritdoc */ protected function setUp() { $this->config = $this->getMockBuilder(Config::class) ->disableOriginalConstructor() ->setMethods(['isActive']) ->getMock(); $this->logger = $this->getMockBuilder(LoggerInterface::class) ->disableOriginalConstructor() ->getMock(); $this->creationService = $this->getMockBuilder(CaseCreationServiceInterface::class) ->disableOriginalConstructor() ->setMethods(['createForOrder']) ->getMock(); $this->observer = $this->getMockBuilder(Observer::class) ->disableOriginalConstructor() ->setMethods(['getEvent']) ->getMock(); $this->event = $this->getMockBuilder(Event::class) ->disableOriginalConstructor() ->setMethods(['getData']) ->getMock(); $this->placeOrder = new PlaceOrder( $this->config, $this->creationService, $this->logger ); } /** * Checks a test case when Signifyd module is disabled. * * @covers \Magento\Signifyd\Observer\PlaceOrder::execute */ public function testExecuteWithDisabledModule() { $orderId = 1; $storeId = 2; $this->withActiveSignifydIntegration(false, $storeId); $this->withOrderEntity($orderId, $storeId); $this->creationService->expects(self::never()) ->method('createForOrder'); $this->placeOrder->execute($this->observer); } /** * Checks a test case when the observer event returns empty an order entity. * * @covers \Magento\Signifyd\Observer\PlaceOrder::execute */ public function testExecuteWithoutOrder() { $this->withActiveSignifydIntegration(true); $this->withOrderEntity(null, null); $this->creationService->expects(self::never()) ->method('createForOrder'); $this->placeOrder->execute($this->observer); } /** * Checks a test case when the order placed with offline payment method. * * @covers \Magento\Signifyd\Observer\PlaceOrder::execute */ public function testExecuteWithOfflinePayment() { $orderId = 1; $storeId = 2; $this->withActiveSignifydIntegration(true, $storeId); $this->withOrderEntity($orderId, $storeId); $this->withAvailablePaymentMethod(false); $this->creationService->expects(self::never()) ->method('createForOrder'); $this->placeOrder->execute($this->observer); } /** * Checks a test case when case creation service fails. * * @covers \Magento\Signifyd\Observer\PlaceOrder::execute */ public function testExecuteWithFailedCaseCreation() { $orderId = 1; $storeId = 2; $exceptionMessage = __('Case with the same order id already exists.'); $this->withActiveSignifydIntegration(true, $storeId); $this->withOrderEntity($orderId, $storeId); $this->withAvailablePaymentMethod(true); $this->creationService->method('createForOrder') ->with(self::equalTo($orderId)) ->willThrowException(new AlreadyExistsException($exceptionMessage)); $this->logger->method('error') ->with(self::equalTo($exceptionMessage)); $result = $this->placeOrder->execute($this->observer); $this->assertNull($result); } /** * Checks a test case when observer successfully calls case creation service. * * @covers \Magento\Signifyd\Observer\PlaceOrder::execute */ public function testExecute() { $orderId = 1; $storeId = 2; $this->withActiveSignifydIntegration(true, $storeId); $this->withOrderEntity($orderId, $storeId); $this->withAvailablePaymentMethod(true); $this->creationService ->method('createForOrder') ->with(self::equalTo($orderId)); $this->logger->expects(self::never()) ->method('error'); $this->placeOrder->execute($this->observer); } public function testExecuteWithOrderPendingPayment() { $orderId = 1; $storeId = 2; $this->withActiveSignifydIntegration(true, $storeId); $this->withOrderEntity($orderId, $storeId); $this->orderEntity->method('getState') ->willReturn(Order::STATE_PENDING_PAYMENT); $this->withAvailablePaymentMethod(true); $this->creationService->expects(self::never()) ->method('createForOrder'); $this->placeOrder->execute($this->observer); } /** * Specifies order entity mock execution. * * @param int|null $orderId * @param int|null $storeId * @return void */ private function withOrderEntity($orderId, $storeId): void { $this->orderEntity = $this->getMockBuilder(OrderInterface::class) ->disableOriginalConstructor() ->getMock(); $this->orderEntity->method('getEntityId') ->willReturn($orderId); $this->orderEntity->method('getStoreId') ->willReturn($storeId); $this->observer->method('getEvent') ->willReturn($this->event); $this->event->method('getData') ->with('order') ->willReturn($this->orderEntity); } /** * Specifies config mock execution. * * @param bool $isActive * @param int|null $storeId * @return void */ private function withActiveSignifydIntegration(bool $isActive, $storeId = null): void { $this->config->method('isActive') ->with($storeId) ->willReturn($isActive); } /** * Specifies payment method mock execution. * * @param bool $isAvailable * @return void */ private function withAvailablePaymentMethod($isAvailable) { /** @var MethodInterface|MockObject $paymentMethod */ $paymentMethod = $this->getMockBuilder(MethodInterface::class) ->disableOriginalConstructor() ->getMock(); /** * The code depends on implementation but not interface * because order payment implements two interfaces */ /** @var Payment|MockObject $orderPayment */ $orderPayment = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() ->getMock(); $this->orderEntity->method('getPayment') ->willReturn($orderPayment); $orderPayment->method('getMethodInstance') ->willReturn($paymentMethod); $paymentMethod->method('isOffline') ->willReturn(!$isAvailable); } }