diff --git a/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php b/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php new file mode 100644 index 000000000..a7e708965 --- /dev/null +++ b/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php @@ -0,0 +1,190 @@ +host = 'https://example.com/'; + $this->bearer = Mockery::mock(Bearer::class); + $this->factory = Mockery::mock(PaymentTokenFactory::class); + $this->logger = Mockery::mock(LoggerInterface::class); + $this->prefix = 'prefix'; + $this->sut = new PaymentTokenEndpoint( + $this->host, + $this->bearer, + $this->factory, + $this->logger, + $this->prefix + ); + } + + public function testForUserReturnsToken() + { + $id = 1; + $token = Mockery::mock(Token::class); + $rawResponse = ['body' => '{"payment_tokens":[{"id": "123abc"}]}']; + $paymentToken = new PaymentToken('foo', 'PAYMENT_METHOD_TOKEN'); + + $this->bearer->shouldReceive('bearer') + ->andReturn($token); + $token->shouldReceive('token') + ->andReturn('bearer'); + + $this->ensureRequestForUser($rawResponse, $id); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200); + + $this->factory->shouldReceive('from_paypal_response') + ->andReturn($paymentToken); + + $result = $this->sut->for_user($id); + $this->assertInstanceOf(PaymentToken::class, $result[0]); + + } + + public function testForUserFailsBecauseOfWpError() + { + $id = 1; + $token = Mockery::mock(Token::class); + $rawResponse = []; + $this->bearer->shouldReceive('bearer') + ->andReturn($token); + $token->shouldReceive('token') + ->andReturn('bearer'); + $this->ensureRequestForUser($rawResponse, $id); + + expect('wp_remote_get')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(true); + $this->logger->shouldReceive('log'); + + $this->expectException(RuntimeException::class); + $this->sut->for_user($id); + } + + public function testForUserFailsBecauseResponseCodeIsNot200() + { + $id = 1; + $token = Mockery::mock(Token::class); + $rawResponse = ['body' => '{"some_error":true}']; + $this->bearer->shouldReceive('bearer') + ->andReturn($token); + $token->shouldReceive('token') + ->andReturn('bearer'); + $this->ensureRequestForUser($rawResponse, $id); + + + expect('wp_remote_get')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500); + $this->logger->shouldReceive('log'); + + $this->expectException(PayPalApiException::class); + $this->sut->for_user($id); + } + + public function testForUserFailBecauseEmptyTokens() + { + $id = 1; + $token = Mockery::mock(Token::class); + $rawResponse = ['body' => '{"payment_tokens":[]}']; + $this->bearer->shouldReceive('bearer') + ->andReturn($token); + $token->shouldReceive('token') + ->andReturn('bearer'); + $this->ensureRequestForUser($rawResponse, $id); + + + expect('wp_remote_get')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200); + $this->logger->shouldReceive('log'); + + $this->expectException(RuntimeException::class); + $this->sut->for_user($id); + } + + public function testDeleteToken() + { + $paymentToken = new PaymentToken('foo', 'PAYMENT_METHOD_TOKEN'); + $token = Mockery::mock(Token::class); + $this->bearer->shouldReceive('bearer') + ->andReturn($token); + $token->shouldReceive('token') + ->andReturn('bearer'); + + expect('wp_remote_get')->andReturn(); + expect('is_wp_error')->andReturn(false); + expect('wp_remote_retrieve_response_code')->andReturn(204); + + $this->sut->delete_token($paymentToken); + } + + public function testDeleteTokenFails() + { + $paymentToken = new PaymentToken('foo', 'PAYMENT_METHOD_TOKEN'); + $token = Mockery::mock(Token::class); + $this->bearer->shouldReceive('bearer') + ->andReturn($token); + $token->shouldReceive('token') + ->andReturn('bearer'); + + expect('wp_remote_get')->andReturn(); + expect('is_wp_error')->andReturn(true); + $this->logger->shouldReceive('log'); + + $this->expectException(RuntimeException::class); + $this->sut->delete_token($paymentToken); + } + + /** + * @param array $rawResponse + * @param int $id + * @throws \Brain\Monkey\Expectation\Exception\ExpectationArgsRequired + */ + private function ensureRequestForUser(array $rawResponse, int $id): void + { + $host = $this->host; + $prefix = $this->prefix; + expect('wp_remote_get')->andReturnUsing( + function ($url, $args) use ($rawResponse, $host, $prefix, $id) { + if ($url !== $host . 'v2/vault/payment-tokens/?customer_id=' . $prefix . $id) { + return false; + } + if ($args['headers']['Authorization'] !== 'Bearer bearer') { + return false; + } + if ($args['headers']['Content-Type'] !== 'application/json') { + return false; + } + + return $rawResponse; + } + ); + } +} diff --git a/tests/PHPUnit/Subscription/RenewalHandlerTest.php b/tests/PHPUnit/Subscription/RenewalHandlerTest.php new file mode 100644 index 000000000..53d5ad0e3 --- /dev/null +++ b/tests/PHPUnit/Subscription/RenewalHandlerTest.php @@ -0,0 +1,86 @@ +logger = Mockery::mock(LoggerInterface::class); + $this->repository = Mockery::mock(PaymentTokenRepository::class); + $this->orderEndpoint = Mockery::mock(OrderEndpoint::class); + $this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class); + $this->payerFactory = Mockery::mock(PayerFactory::class); + + $this->sut = new RenewalHandler( + $this->logger, + $this->repository, + $this->orderEndpoint, + $this->purchaseUnitFactory, + $this->payerFactory + ); + } + + public function testRenewProcessOrder() + { + $wcOrder = Mockery::mock(\WC_Order::class); + $customer = Mockery::mock('overload:WC_Customer'); + $token = Mockery::mock(PaymentToken::class); + $purchaseUnit = Mockery::mock(PurchaseUnit::class); + $payer = Mockery::mock(Payer::class); + $order = Mockery::mock(Order::class); + + $this->logger->shouldReceive('log'); + $wcOrder + ->shouldReceive('get_id') + ->andReturn(1); + $wcOrder + ->shouldReceive('get_customer_id') + ->andReturn(1); + $this->repository->shouldReceive('for_user_id') + ->andReturn($token); + $customer->shouldReceive('get_id') + ->andReturn(1); + $this->purchaseUnitFactory->shouldReceive('from_wc_order') + ->andReturn($purchaseUnit); + $this->payerFactory->shouldReceive('from_customer') + ->andReturn($payer); + + $this->orderEndpoint->shouldReceive('create') + ->with([$purchaseUnit], $payer, $token) + ->andReturn($order); + + $order->shouldReceive('intent') + ->andReturn('CAPTURE'); + $order->shouldReceive('status->is') + ->andReturn(true); + $wcOrder->shouldReceive('update_status'); + + $this->sut->renew($wcOrder); + } +} diff --git a/tests/PHPUnit/Subscription/Repository/PaymentTokenRepositoryTest.php b/tests/PHPUnit/Subscription/Repository/PaymentTokenRepositoryTest.php new file mode 100644 index 000000000..bd22a3047 --- /dev/null +++ b/tests/PHPUnit/Subscription/Repository/PaymentTokenRepositoryTest.php @@ -0,0 +1,88 @@ +factory = Mockery::mock(PaymentTokenFactory::class); + $this->endpoint = Mockery::mock(PaymentTokenEndpoint::class); + $this->sut = new PaymentTokenRepository($this->factory, $this->endpoint); + } + + public function testForUserIdFromArray() + { + $id = 1; + $token = ['id' => 'foo']; + $paymentToken = new PaymentToken('foo', 'PAYMENT_METHOD_TOKEN'); + + expect('get_user_meta')->with($id, $this->sut::USER_META, true) + ->andReturn($token); + + $this->factory->shouldReceive('from_array')->with($token) + ->andReturn($paymentToken); + + $result = $this->sut->for_user_id($id); + $this->assertInstanceOf(PaymentToken::class, $result); + } + + public function testFetchForUserId() + { + $id = 1; + $paymentToken = new PaymentToken('foo', 'PAYMENT_METHOD_TOKEN'); + + when('get_user_meta')->justReturn([]); + $this->endpoint->shouldReceive('for_user') + ->with($id) + ->andReturn([$paymentToken]); + expect('update_user_meta')->with($id, $this->sut::USER_META, $paymentToken->to_array()); + + $result = $this->sut->for_user_id($id); + $this->assertInstanceOf(PaymentToken::class, $result); + } + + public function testForUserIdFails() + { + $id = 1; + when('get_user_meta')->justReturn([]); + + $this->endpoint + ->expects('for_user') + ->with($id) + ->andThrow(RuntimeException::class); + + $result = $this->sut->for_user_id($id); + $this->assertNull($result); + } + + public function testDeleteToken() + { + $id = 1; + $paymentToken = new PaymentToken('foo', 'PAYMENT_METHOD_TOKEN'); + + expect('delete_user_meta')->with($id, $this->sut::USER_META); + $this->endpoint->shouldReceive('delete_token') + ->with($paymentToken); + + $this->sut->delete_token($id, $paymentToken); + } +} diff --git a/tests/PHPUnit/bootstrap.php b/tests/PHPUnit/bootstrap.php index 28e53866b..ba6ffb319 100644 --- a/tests/PHPUnit/bootstrap.php +++ b/tests/PHPUnit/bootstrap.php @@ -2,4 +2,5 @@ declare(strict_types=1); require_once __DIR__ . '/../../vendor/autoload.php'; require_once __DIR__ . '/../stubs/WC_Payment_Gateway.php'; -require_once __DIR__ . '/../stubs/WC_Ajax.php'; \ No newline at end of file +require_once __DIR__ . '/../stubs/WC_Payment_Gateway_CC.php'; +require_once __DIR__ . '/../stubs/WC_Ajax.php'; diff --git a/tests/stubs/WC_Payment_Gateway_CC.php b/tests/stubs/WC_Payment_Gateway_CC.php new file mode 100644 index 000000000..f2e36b984 --- /dev/null +++ b/tests/stubs/WC_Payment_Gateway_CC.php @@ -0,0 +1,7 @@ +