diff --git a/.codegenignore b/.codegenignore new file mode 100644 index 0000000..448a8c5 --- /dev/null +++ b/.codegenignore @@ -0,0 +1,10 @@ +tests/E2E/** +tests/UnitTests/** +tests/ClientFactory.php +tests/WebDriverUtilities.php +tests/bootstrap.php +tests/Controllers/BaseTestController.php +.gitignore +.github/** +phpunit.xml +selenium.jar \ No newline at end of file diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml new file mode 100644 index 0000000..5c9210a --- /dev/null +++ b/.github/workflows/test-runner.yml @@ -0,0 +1,46 @@ +name: Tests + +on: + workflow_dispatch: + +jobs: + test: + name: Running all tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + + - name: Install dependencies + run: | + composer install + composer require php-webdriver/webdriver --dev + composer require phpunit/phpunit --dev + + - name: Run Lint Tests + run: composer lint + + - name: Run Analyzer Tests + run: composer analyze + + - name: Set up Java 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Run Selenium Server + run: java -jar selenium.jar standalone & + + - name: Run tests + run: ./vendor/bin/phpunit --testdox + env: + CLIENT_ID: ${{ secrets.CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + EMAIL: ${{ secrets.EMAIL }} + PASSWORD: ${{ secrets.PASSWORD }} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..2260126 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ + + + + + ./tests + + + + + + + + src + + + diff --git a/selenium.jar b/selenium.jar new file mode 100644 index 0000000..7e82109 Binary files /dev/null and b/selenium.jar differ diff --git a/src/PaypalServerSdkClient.php b/src/PaypalServerSDKClient.php similarity index 100% rename from src/PaypalServerSdkClient.php rename to src/PaypalServerSDKClient.php diff --git a/src/PaypalServerSdkClientBuilder.php b/src/PaypalServerSDKClientBuilder.php similarity index 100% rename from src/PaypalServerSdkClientBuilder.php rename to src/PaypalServerSDKClientBuilder.php diff --git a/tests/ClientFactory.php b/tests/ClientFactory.php new file mode 100644 index 0000000..f229e8b --- /dev/null +++ b/tests/ClientFactory.php @@ -0,0 +1,58 @@ +httpCallback($httpCallback)->build(); + } + + public static function addTestConfiguration(PaypalServerSDKClientBuilder $builder): PaypalServerSDKClientBuilder + { + return $builder; + } + + public static function addConfigurationFromEnvironment( + PaypalServerSDKClientBuilder $builder + ): PaypalServerSDKClientBuilder { + $timeout = '10000'; + $environment = Environment::SANDBOX; + $oAuthClientId = getenv('CLIENT_ID'); + $oAuthClientSecret = getenv('CLIENT_SECRET'); + + if (!empty($timeout) && \is_numeric($timeout)) { + $builder->timeout(intval($timeout)); + } + + if (!empty($environment)) { + $builder->environment($environment); + } + + if (!empty($oAuthClientId) && !empty($oAuthClientSecret)) { + $builder->clientCredentialsAuthCredentials( + ClientCredentialsAuthCredentialsBuilder::init($oAuthClientId, $oAuthClientSecret) + ); + } + + return $builder; + } +} diff --git a/tests/Controllers/BaseTestController.php b/tests/Controllers/BaseTestController.php new file mode 100644 index 0000000..f263298 --- /dev/null +++ b/tests/Controllers/BaseTestController.php @@ -0,0 +1,36 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '100.00' + )->build() + ) + ->referenceId('d9f80740-38f0-11e8-b467-0ed5f89f718b') + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build() + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testCaptureOrder(Order $orderDetail): Order + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCaptureOrder + */ + public function testCreateOrderTrack(Order $captureDetail): Order + { + $purchaseUnits = $captureDetail->getPurchaseUnits(); + $captureId = null; + if (isset($purchaseUnits)) { + $captures = $purchaseUnits[0]->getPayments()->getCaptures(); + if (isset($captures)) { + $captureId = $captures[0]->getId(); + } + } + $this->assertNotNull($captureId); + $request = [ + 'id' => $captureDetail->getId(), + 'body' => OrderTrackerRequestBuilder::init($captureId ?? '') + ->trackingNumber('443844607820') + ->carrier(ShipmentCarrier::FEDEX) + ->notifyPayer(false) + ->items( + [ + OrderTrackerItemBuilder::init() + ->name('T-Shirt') + ->quantity('1') + ->sku('sku02') + ->url('https://www.example.com/example') + ->imageUrl('https://www.example.com/example.jpg') + ->upc(UniversalProductCodeBuilder::init(UPCType::UPCA, 'upc001')->build()) + ->build() + ] + ) + ->build(), + ]; + + $response = self::$ordersController->ordersTrackCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrderTrack + */ + public function testUpdateOrderTrack(Order $shippingOrder): void + { + $purchaseUnits = $shippingOrder->getPurchaseUnits(); + $trackerId = null; + if (isset($purchaseUnits)) { + $trackers = $purchaseUnits[0]->getShipping()->getTrackers(); + if (isset($trackers)) { + $trackerId = $trackers[0]->getId(); + } + } + $this->assertNotNull($trackerId); + $request = [ + 'id' => $shippingOrder->getId(), + 'trackerId' => $trackerId ?? '', + 'body' => [ + PatchBuilder::init( + PatchOp::REPLACE + ) + ->path('/notify_payer') + ->value(true) + ->build() + ] + ]; + + $response = self::$ordersController->ordersTrackersPatch($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(204, $response->getStatusCode()); + } +} diff --git a/tests/E2E/AuthenticationMultiStepFlowTest.php b/tests/E2E/AuthenticationMultiStepFlowTest.php new file mode 100644 index 0000000..b3abfa7 --- /dev/null +++ b/tests/E2E/AuthenticationMultiStepFlowTest.php @@ -0,0 +1,220 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '10.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '10.00' + )->build() + )->build() + )->build() + ) + ->description('Camera Shop') + ->customId('testcustom_id') + ->invoiceId('invoice_number_' . rand(1, 99999999999)) + ->items([ + ItemBuilder::init( + 'Levis 501 Selvedge STF', + MoneyBuilder::init( + 'USD', + '5.00' + )->build(), + '1' + ) + ->tax(MoneyBuilder::init( + 'USD', + '0.00' + )->build()) + ->sku('5158936') + ->build(), + ItemBuilder::init( + 'T-Shirt', + MoneyBuilder::init( + 'USD', + '5.00' + )->build(), + '1' + ) + ->tax(MoneyBuilder::init( + 'USD', + '0.00' + )->build()) + ->sku('1457432') + ->build() + ]) + ->build() + ] + )->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'payPalPartnerAttributionId' => 'PayPal-Partner-Attribution-Id', + 'payPalClientMetadataId' => 'PayPal-Client-Metadata-Id', + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + */ + public function testCaptureOrder(Order $orderDetail): ?string + { + $request = [ + 'id' => $orderDetail->getId(), + 'prefer' => 'return=representation', + 'body' => OrderCaptureRequestBuilder::init() + ->paymentSource( + OrderCaptureRequestPaymentSourceBuilder::init() + ->card( + CardRequestBuilder::init() + ->name('John Doe') + ->number('4868719460707704') + ->expiry('2027-02') + ->billingAddress( + AddressBuilder::init( + 'US' + ) + ->addressLine1('2211 N First Street') + ->adminArea1('CA') + ->adminArea2('San Jose') + ->postalCode('95131') + ->build() + ) + ->attributes( + CardAttributesBuilder::init() + ->verification( + CardVerificationBuilder::init() + ->method(CardVerificationMethod::SCA_ALWAYS) + ->build() + ) + ->build() + ) + ->experienceContext(CardExperienceContextBuilder::init() + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->build()) + ->build() + ) + ->build() + ) + ->build() + ]; + + $response = self::$ordersController->ordersCapture($request); + + // TODO: Verify status 422, as its currently considered as a success case + $this->assertTrue($response->isError()); + $this->assertEquals(422, $response->getStatusCode()); + + return $response->getResult()['links'][0]->href; + } + + /** + * @depends testCaptureOrder + * @throws Exception + */ + public function testCompleteHeliosVerification(?string $href): void + { + $this->assertNotNull($href); + WebDriverUtilities::completeHeliosVerification($href ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompleteHeliosVerification + */ + public function testCaptureOrderAgain(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + } + + /** + * @depends testCreateOrder + * @depends testCaptureOrderAgain + */ + public function testGetOrderDetails(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId() + ]; + + $response = self::$ordersController->ordersGet($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('COMPLETED', $response->getResult()->getStatus()); + } +} diff --git a/tests/E2E/AuthenticationSingleStepFlowTest.php b/tests/E2E/AuthenticationSingleStepFlowTest.php new file mode 100644 index 0000000..9a6c7e2 --- /dev/null +++ b/tests/E2E/AuthenticationSingleStepFlowTest.php @@ -0,0 +1,205 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '10.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '10.00' + )->build() + )->build() + )->build() + ) + ->description('Camera Shop') + ->customId('testcustom_id') + ->invoiceId('invoice_number_' . rand(1, 99999999999)) + ->items([ + ItemBuilder::init( + 'Levis 501 Selvedge STF', + MoneyBuilder::init( + 'USD', + '5.00' + )->build(), + '1' + ) + ->tax(MoneyBuilder::init( + 'USD', + '0.00' + )->build()) + ->sku('5158936') + ->build(), + ItemBuilder::init( + 'T-Shirt', + MoneyBuilder::init( + 'USD', + '5.00' + )->build(), + '1' + ) + ->tax(MoneyBuilder::init( + 'USD', + '0.00' + )->build()) + ->sku('1457432') + ->build() + ]) + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->card( + CardRequestBuilder::init() + ->name('John Doe') + ->number('4868719995056080') + ->expiry('2027-02') + ->billingAddress( + AddressBuilder::init( + 'US' + ) + ->addressLine1('2211 N First Street') + ->adminArea1('CA') + ->adminArea2('San Jose') + ->postalCode('95131') + ->build() + ) + ->attributes( + CardAttributesBuilder::init() + ->verification( + CardVerificationBuilder::init() + ->method(CardVerificationMethod::SCA_ALWAYS) + ->build() + ) + ->build() + ) + ->experienceContext(CardExperienceContextBuilder::init() + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->build()) + ->build() + ) + ->build() + ) + ->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'payPalPartnerAttributionId' => 'PayPal-Partner-Attribution-Id', + 'payPalClientMetadataId' => 'PayPal-Client-Metadata-Id', + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompleteHeliosVerification(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completeHeliosVerification($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompleteHeliosVerification + */ + public function testCaptureOrder(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + } + + /** + * @depends testCreateOrder + * @depends testCaptureOrder + */ + public function getOrderDetails(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId() + ]; + + $response = self::$ordersController->ordersGet($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertNotNull($response->getResult()->getPaymentSource()); + $this->assertEquals('COMPLETED', $response->getResult()->getStatus()); + } +} diff --git a/tests/E2E/AuthorizeAndCaptureFlowTest.php b/tests/E2E/AuthorizeAndCaptureFlowTest.php new file mode 100644 index 0000000..855a4e9 --- /dev/null +++ b/tests/E2E/AuthorizeAndCaptureFlowTest.php @@ -0,0 +1,232 @@ +getOrdersController(); + self::$paymentsController = $client->getPaymentsController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::AUTHORIZE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '25.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '25.00' + )->build() + ) + ->shipping( + MoneyBuilder::init( + 'USD', + '0' + )->build() + ) + ->taxTotal( + MoneyBuilder::init( + 'USD', + '0' + )->build() + ) + ->build() + )->build() + ) + ->description('Clothing Shop') + ->items([ + ItemBuilder::init( + 'Levis 501', + MoneyBuilder::init( + 'USD', + '25.00' + )->build(), + '1' + ) + ->tax( + MoneyBuilder::init( + 'USD', + '0.00' + )->build() + ) + ->sku('5158936') + ->build() + ]) + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build() + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testAuthorizeOrder(Order $orderDetail): OrderAuthorizeResponse + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersAuthorize($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testAuthorizeOrder + */ + public function testCaptureAuthorization(OrderAuthorizeResponse $authorizeResponse): CapturedPayment + { + $purchaseUnits = $authorizeResponse->getPurchaseUnits(); + $authorizationId = null; + if (isset($purchaseUnits)) { + $authorizations = $purchaseUnits[0]->getPayments()->getAuthorizations(); + if (isset($authorizations)) { + $authorizationId = $authorizations[0]->getId(); + } + } + $this->assertNotNull($authorizationId); + $request = [ + 'authorizationId' => $authorizationId, + 'prefer' => 'return=representation' + ]; + + $response = self::$paymentsController->authorizationsCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testAuthorizeOrder + */ + public function testGetAuthorization(OrderAuthorizeResponse $authorizeResponse): void + { + $purchaseUnits = $authorizeResponse->getPurchaseUnits(); + $authorizationId = null; + if (isset($purchaseUnits)) { + $authorizations = $purchaseUnits[0]->getPayments()->getAuthorizations(); + if (isset($authorizations)) { + $authorizationId = $authorizations[0]->getId(); + } + } + $this->assertNotNull($authorizationId); + $response = self::$paymentsController->authorizationsGet($authorizationId ?? ''); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('CAPTURED', $response->getResult()->getStatus()); + } + + /** + * @depends testCaptureAuthorization + */ + public function testCapturePayment(CapturedPayment $capturedPayment): void + { + $response = self::$paymentsController->capturesGet($capturedPayment->getId() ?? ''); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('COMPLETED', $response->getResult()->getStatus()); + } +} diff --git a/tests/E2E/ConfirmOrderFlowTest.php b/tests/E2E/ConfirmOrderFlowTest.php new file mode 100644 index 0000000..841e670 --- /dev/null +++ b/tests/E2E/ConfirmOrderFlowTest.php @@ -0,0 +1,169 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '100.00' + )->build() + ) + ->referenceId('d9f80740-38f0-11e8-b467-0ed5f89f718b') + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + */ + public function testConfirmOrder(Order $orderDetail): Order + { + $request = [ + 'id' => $orderDetail->getId(), + 'prefer' => 'return=representation', + 'body' => ConfirmOrderRequestBuilder::init( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->emailAddress('customer@example.com') + ->name( + NameBuilder::init() + ->givenName('John') + ->surname('Doe') + ->build() + ) + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->brandName('EXAMPLE INC') + ->locale('en-US') + ->shippingPreference(ShippingPreference::SET_PROVIDED_ADDRESS) + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->userAction(PayPalExperienceUserAction::PAY_NOW) + ->paymentMethodPreference(PayeePaymentMethodPreference::IMMEDIATE_PAYMENT_REQUIRED) + ->build() + )->build() + )->build() + )->build() + ]; + + $response = self::$ordersController->ordersConfirm($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testConfirmOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testCaptureOrder(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + $this->assertEquals('COMPLETED', $response->getResult()->getStatus()); + } +} diff --git a/tests/E2E/PatchOrderFlowTest.php b/tests/E2E/PatchOrderFlowTest.php new file mode 100644 index 0000000..dad8b84 --- /dev/null +++ b/tests/E2E/PatchOrderFlowTest.php @@ -0,0 +1,210 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '10.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '10.00' + )->build() + ) + ->shipping( + MoneyBuilder::init( + 'USD', + '0.00' + )->build() + ) + ->taxTotal( + MoneyBuilder::init( + 'USD', + '0' + )->build() + )->build() + )->build() + ) + ->description('Camera Shop') + ->items([ + ItemBuilder::init( + 'Levis 501 Selvedge STF', + MoneyBuilder::init( + 'USD', + '5.00' + )->build(), + '1' + ) + ->tax(MoneyBuilder::init( + 'USD', + '0.00' + )->build()) + ->sku('5158936') + ->build(), + ItemBuilder::init( + 'T-Shirt', + MoneyBuilder::init( + 'USD', + '5.00' + )->build(), + '1' + ) + ->tax(MoneyBuilder::init( + 'USD', + '0.00' + )->build()) + ->sku('1457432') + ->build() + ]) + ->shipping( + ShippingDetailsBuilder::init() + ->address( + AddressBuilder::init( + 'US' + ) + ->addressLine1('123 Main Street') + ->adminArea1('CA') + ->adminArea2('San Jose') + ->postalCode('95131') + ->build() + )->build() + )->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + */ + public function testPatchOrder(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId(), + 'body' => [ + PatchBuilder::init( + PatchOp::REPLACE + ) + ->path("/purchase_units/@reference_id==d'default'/shipping/address") + ->value([ + 'address_line_1' => '1234 Main St', + 'address_line_2' => 'Floor 6', + 'admin_area_2' => 'San Francisco', + 'admin_area_1' => 'CA', + 'postal_code' => '94107', + 'country_code' => 'US', + ]) + ->build() + ] + ]; + + $response = self::$ordersController->ordersPatch($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(204, $response->getStatusCode()); + } + + /** + * @depends testCreateOrder + * @depends testPatchOrder + */ + public function testGetOrderDetails(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId() + ]; + + $response = self::$ordersController->ordersGet($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + $this->assertEquals( + '1234 Main St', + $response->getResult() + ->getPurchaseUnits()[0] + ->getShipping() + ->getAddress() + ->getAddressLine1() + ); + } +} diff --git a/tests/E2E/PaymentMethodWithPurchaseFlowTest.php b/tests/E2E/PaymentMethodWithPurchaseFlowTest.php new file mode 100644 index 0000000..9ab8a0e --- /dev/null +++ b/tests/E2E/PaymentMethodWithPurchaseFlowTest.php @@ -0,0 +1,169 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '10.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '10.00' + )->build() + ) + ->build() + )->build() + ) + ->description('Camera Shop') + ->items([ + ItemBuilder::init( + 'Camera', + MoneyBuilder::init( + 'USD', + '10.00' + )->build(), + '1' + )->build() + ]) + ->shipping( + ShippingDetailsBuilder::init() + ->address( + AddressBuilder::init( + 'US' + ) + ->addressLine1('500 Main Street') + ->addressLine2('#1000') + ->adminArea1('CA') + ->adminArea2('San Jose') + ->postalCode('95131') + ->build() + )->build() + )->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->attributes(PayPalWalletAttributesBuilder::init() + ->vault( + PayPalWalletVaultInstructionBuilder::init( + PayPalPaymentTokenUsageType::MERCHANT + ) + ->storeInVault(StoreInVaultInstruction::ON_SUCCESS) + ->build() + )->build()) + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->shippingPreference(ShippingPreference::SET_PROVIDED_ADDRESS) + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->build() + ) + ->build() + ) + ->build() + ) + ->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testCaptureOrder(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + } +} diff --git a/tests/E2E/PaymentMethodWithoutPurchaseFlowTest.php b/tests/E2E/PaymentMethodWithoutPurchaseFlowTest.php new file mode 100644 index 0000000..0536985 --- /dev/null +++ b/tests/E2E/PaymentMethodWithoutPurchaseFlowTest.php @@ -0,0 +1,231 @@ +getOrdersController(); + self::$vaultController = $client->getVaultController(); + } + + public function testCreateSetupToken(): SetupTokenResponse + { + $request = [ + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'body' => SetupTokenRequestBuilder::init( + SetupTokenRequestPaymentSourceBuilder::init() + ->paypal( + VaultPayPalWalletRequestBuilder::init() + ->description('Description for PayPal to be shown to PayPal payer') + ->permitMultiplePaymentTokens(true) + ->usageType('MERCHANT') + ->customerType('CONSUMER') + ->experienceContext( + VaultExperienceContextBuilder::init() + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->build() + ) + ->build() + )->build() + )->build() + ]; + + $response = self::$vaultController->setupTokensCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateSetupToken + * @throws Exception + */ + public function testSavePaymentMethod(SetupTokenResponse $setupTokenDetail): void + { + $links = $setupTokenDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::savePaymentMethod($url ?? ''); + } + + /** + * @depends testCreateSetupToken + * @depends testSavePaymentMethod + */ + public function testCreatePaymentToken(SetupTokenResponse $setupTokenResponse): PaymentTokenResponse + { + $request = [ + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'body' => PaymentTokenRequestBuilder::init( + PaymentTokenRequestPaymentSourceBuilder::init() + ->token( + VaultTokenRequestBuilder::init( + $setupTokenResponse->getId() ?? '', + TokenRequestType::SETUP_TOKEN + )->build() + )->build() + )->build() + ]; + + $response = self::$vaultController->paymentTokensCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreatePaymentToken + */ + public function testCreateOrder(PaymentTokenResponse $paymentToken): void + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '10.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '10.00' + )->build() + )->build() + )->build() + ) + ->description('Camera Shop') + ->items([ + ItemBuilder::init( + 'Camera', + MoneyBuilder::init( + 'USD', + '10.00' + )->build(), + '1' + )->build(), + ]) + ->shipping( + ShippingDetailsBuilder::init() + ->address( + AddressBuilder::init( + 'US' + ) + ->addressLine1('500 Main Street') + ->addressLine2('#1000') + ->adminArea1('CA') + ->adminArea2('San Jose') + ->postalCode('95131') + ->build() + )->build() + )->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->vaultId($paymentToken->getId()) + ->build() + ) + ->build() + ) + ->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + } + + /** + * @depends testCreateSetupToken + * @depends testCreateOrder + */ + public function testGetSetupToken(SetupTokenResponse $setupTokenDetail): void + { + $response = self::$vaultController->setupTokensGet($setupTokenDetail->getId() ?? ''); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('VAULTED', $response->getResult()->getStatus()); + } + + /** + * @depends testCreatePaymentToken + * @depends testGetSetupToken + */ + public function testGetPaymentToken(PaymentTokenResponse $paymentToken): void + { + $response = self::$vaultController->paymentTokensGet($paymentToken->getId() ?? ''); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertNotNull($response); + } +} diff --git a/tests/E2E/RefundFlowTest.php b/tests/E2E/RefundFlowTest.php new file mode 100644 index 0000000..c266537 --- /dev/null +++ b/tests/E2E/RefundFlowTest.php @@ -0,0 +1,167 @@ +getOrdersController(); + self::$paymentsController = $client->getPaymentsController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '100.00' + )->build() + ) + ->referenceId('d9f80740-38f0-11e8-b467-0ed5f89f718b') + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build() + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testCaptureOrder(Order $orderDetail): Order + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCaptureOrder + */ + public function testRefund(Order $captureDetail): Refund + { + $purchaseUnits = $captureDetail->getPurchaseUnits(); + $captureId = null; + if (isset($purchaseUnits)) { + $captures = $purchaseUnits[0]->getPayments()->getCaptures(); + if (isset($captures)) { + $captureId = $captures[0]->getId(); + } + } + $this->assertNotNull($captureId); + $request = [ + 'captureId' => $captureId, + 'prefer' => 'return=representation' + ]; + + $response = self::$paymentsController->capturesRefund($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testRefund + */ + public function testGetRefund(Refund $refund): void + { + $response = self::$paymentsController->refundsGet($refund->getId() ?? ''); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('COMPLETED', $response->getResult()->getStatus()); + } +} diff --git a/tests/E2E/StandardCheckoutFlowTest.php b/tests/E2E/StandardCheckoutFlowTest.php new file mode 100644 index 0000000..0e734ef --- /dev/null +++ b/tests/E2E/StandardCheckoutFlowTest.php @@ -0,0 +1,134 @@ +getOrdersController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '100.00' + )->build() + ) + ->referenceId('d9f80740-38f0-11e8-b467-0ed5f89f718b') + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build() + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testCaptureOrder(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + } + + /** + * @depends testCreateOrder + * @depends testCaptureOrder + */ + public function testGetOrderDetails(Order $orderDetail): void + { + $request = [ + 'id' => $orderDetail->getId() + ]; + + $response = self::$ordersController->ordersGet($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + } +} diff --git a/tests/E2E/VoidAuthorizationFlowTest.php b/tests/E2E/VoidAuthorizationFlowTest.php new file mode 100644 index 0000000..bc5be44 --- /dev/null +++ b/tests/E2E/VoidAuthorizationFlowTest.php @@ -0,0 +1,197 @@ +getOrdersController(); + self::$paymentsController = $client->getPaymentsController(); + } + + public function testCreateOrder(): Order + { + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::AUTHORIZE, + [ + PurchaseUnitRequestBuilder::init( + AmountWithBreakdownBuilder::init( + 'USD', + '25.00' + ) + ->breakdown( + AmountBreakdownBuilder::init() + ->itemTotal( + MoneyBuilder::init( + 'USD', + '25.00' + )->build() + ) + ->shipping( + MoneyBuilder::init( + 'USD', + '0' + )->build() + ) + ->taxTotal( + MoneyBuilder::init( + 'USD', + '0' + )->build() + ) + ->build() + )->build() + ) + ->description('Clothing Shop') + ->items([ + ItemBuilder::init( + 'Levis 501', + MoneyBuilder::init( + 'USD', + '25.00' + )->build(), + '1' + ) + ->tax( + MoneyBuilder::init( + 'USD', + '0.00' + )->build() + ) + ->sku('5158936') + ->build() + ]) + ->build() + ] + ) + ->paymentSource( + PaymentSourceBuilder::init() + ->paypal( + PayPalWalletBuilder::init() + ->experienceContext( + PayPalWalletExperienceContextBuilder::init() + ->locale('en-US') + ->returnUrl('https://example.com/returnUrl') + ->cancelUrl('https://example.com/cancelUrl') + ->landingPage(PayPalExperienceLandingPage::LOGIN) + ->build() + ) + ->build() + ) + ->build() + ) + ->build(), + 'payPalRequestId' => strval(rand(1, 99999999999)) + ]; + + $response = self::$ordersController->ordersCreate($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(200, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testCreateOrder + * @throws Exception + */ + public function testCompletePayment(Order $orderDetail): void + { + $links = $orderDetail->getLinks(); + $url = null; + if (isset($links)) { + $url = $links[1]->getHref(); + } + $this->assertNotNull($url); + WebDriverUtilities::completePayment($url ?? ''); + } + + /** + * @depends testCreateOrder + * @depends testCompletePayment + */ + public function testAuthorizeOrder(Order $orderDetail): OrderAuthorizeResponse + { + $request = [ + 'id' => $orderDetail->getId(), + 'payPalRequestId' => strval(rand(1, 99999999999)), + 'prefer' => 'return=representation' + ]; + + $response = self::$ordersController->ordersAuthorize($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + + return $response->getResult(); + } + + /** + * @depends testAuthorizeOrder + */ + public function testCaptureAuthorization(OrderAuthorizeResponse $authorizeResponse): void + { + $purchaseUnits = $authorizeResponse->getPurchaseUnits(); + $authorizationId = null; + if (isset($purchaseUnits)) { + $authorizations = $purchaseUnits[0]->getPayments()->getAuthorizations(); + if (isset($authorizations)) { + $authorizationId = $authorizations[0]->getId(); + } + } + $this->assertNotNull($authorizationId); + $request = [ + 'authorizationId' => $authorizationId, + 'prefer' => 'return=representation' + ]; + + $response = self::$paymentsController->authorizationsCapture($request); + + $this->assertTrue($response->isSuccess()); + $this->assertEquals(201, $response->getStatusCode()); + } +} diff --git a/tests/UnitTests/OrdersControllerTest.php b/tests/UnitTests/OrdersControllerTest.php new file mode 100644 index 0000000..d0d9a36 --- /dev/null +++ b/tests/UnitTests/OrdersControllerTest.php @@ -0,0 +1,209 @@ +getOrdersController(); + } + + public function testOrdersCreateWithStatus400() + { + // Parameters for the API call + $request = [ + 'body' => OrderRequestBuilder::init( + CheckoutPaymentIntent::CAPTURE, + [] + )->build(), + 'payPalRequestId' => 'PayPal-Request-Id', + 'payPalPartnerAttributionId' => 'PayPal-Partner-Attribution-Id2', + 'payPalClientMetadataId' => 'PayPal-Client-Metadata-Id', + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->ordersCreate($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testOrdersPatchWithStatus400() + { + // Parameters for the API call + $request = [ + 'body' => PatchBuilder::init( + PatchOp::ADD + )->build(), + 'id' => self::NON_EXISTENT_ORDER_ID, + ]; + // Perform API call + $result = self::$controller->ordersPatch($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testOrdersGetWithStatus204() + { + // Parameters for the API call + $request = [ + 'id' => self::NON_EXISTENT_ORDER_ID + ]; + // Perform API call + $result = self::$controller->ordersPatch($request); + + // Assert result with expected response + $this->assertTrue($result->isSuccess()); + $this->newTestCase($result->getResult()) + ->expectStatus(204) + ->assert(); + } + + public function testOrdersConfirmWithStatus404() + { + // Parameters for the API call + $request = [ + 'body' => ConfirmOrderRequestBuilder::init( + PaymentSourceBuilder::init()->build() + )->build(), + 'id' => self::NON_EXISTENT_ORDER_ID, + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->ordersConfirm($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testOrdersAuthorizeWithStatus404() + { + // Parameters for the API call + $request = [ + 'id' => self::NON_EXISTENT_ORDER_ID, + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->ordersAuthorize($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testOrdersTrackCreateWithStatus404() + { + // Parameters for the API call + $request = [ + 'id' => self::NON_EXISTENT_ORDER_ID, + 'body' => OrderTrackerRequestBuilder::init( + self::ALREADY_CAPTURED_ID + )->notifyPayer(false)->build(), + ]; + // Perform API call + $result = self::$controller->ordersTrackCreate($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testOrdersTrackersPatchWithStatus404() + { + // Parameters for the API call + $request = [ + 'id' => self::NON_EXISTENT_ORDER_ID, + 'trackerId' => self::NON_EXISTENT_TRACKER_ID, + 'body' => [ + PatchBuilder::init( + PatchOp::REPLACE + ) + ->path('/notify_payer') + ->value(true) + ->build() + ] + ]; + // Perform API call + $result = self::$controller->ordersTrackersPatch($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } +} diff --git a/tests/UnitTests/PaymentsControllerTest.php b/tests/UnitTests/PaymentsControllerTest.php new file mode 100644 index 0000000..14c97a6 --- /dev/null +++ b/tests/UnitTests/PaymentsControllerTest.php @@ -0,0 +1,208 @@ +getPaymentsController(); + } + + public function testAuthorizationsGetWithStatus404() + { + // Perform API call + $result = self::$controller->authorizationsGet(self::NON_EXISTENT_AUTHORIZATION_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json;charset=UTF-8', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testCapturesGetWithStatus404() + { + // Perform API call + $result = self::$controller->capturesGet(self::NON_EXISTENT_CAPTURE_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json;charset=UTF-8', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testRefundsGetWithStatus404() + { + // Perform API call + $result = self::$controller->refundsGet(self::NON_EXISTENT_REFUND_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testAuthorizationsCaptureWithStatus404() + { + // Parameters for the API call + $request = [ + 'body' => CaptureRequestBuilder::init()->finalCapture(false)->build(), + 'authorizationId' => self::NON_EXISTENT_AUTHORIZATION_ID, + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->authorizationsCapture($request); + + $headers = []; + $headers['Content-Type'] = ['application/json;charset=UTF-8', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testAuthorizationsReauthorizeWithStatus404() + { + // Parameters for the API call + $request = [ + 'authorizationId' => self::NON_EXISTENT_AUTHORIZATION_ID, + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->authorizationsReauthorize($request); + + $headers = []; + $headers['Content-Type'] = ['application/json;charset=UTF-8', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testAuthorizationsVoidWithStatus404() + { + // Parameters for the API call + $request = [ + 'authorizationId' => self::NON_EXISTENT_AUTHORIZATION_ID, + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->authorizationsVoid($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testAuthorizationsVoidWithStatus422() + { + // Parameters for the API call + $request = [ + 'authorizationId' => self::ALREADY_AUTHORIZED_ID, + 'prefer' => 'return=minimal' + ]; + // Perform API call + $result = self::$controller->authorizationsVoid($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(422) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testCapturesRefundWithStatus404() + { + // Parameters for the API call + $request = [ + 'captureId' => self::NON_EXISTENT_CAPTURE_ID, + 'prefer' => 'return=minimal', + 'body' => RefundRequestBuilder::init() + ->amount( + MoneyBuilder::init( + 'USD', + '1.44' + )->build() + ) + ->noteToPayer('Defective product') + ->build() + ]; + // Perform API call + $result = self::$controller->capturesRefund($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } +} diff --git a/tests/UnitTests/VaultControllerTest.php b/tests/UnitTests/VaultControllerTest.php new file mode 100644 index 0000000..d800923 --- /dev/null +++ b/tests/UnitTests/VaultControllerTest.php @@ -0,0 +1,242 @@ +getVaultController(); + } + + public function testSetupTokensCreateWithStatus400() + { + // Parameters for the API call + $request = [ + 'payPalRequestId' => '', + 'body' => SetupTokenRequestBuilder::init( + SetupTokenRequestPaymentSourceBuilder::init()->build() + )->build() + ]; + // Perform API call + $result = self::$controller->setupTokensCreate($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testPaymentTokensCreateWithStatus404() + { + // Parameters for the API call + $request = [ + 'body' => PaymentTokenRequestBuilder::init( + PaymentTokenRequestPaymentSourceBuilder::init()->build() + )->build(), + 'payPalRequestId' => '', + ]; + // Perform API call + $result = self::$controller->paymentTokensCreate($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testPaymentTokensCreateWithStatus400() + { + // Parameters for the API call + $request = [ + 'body' => PaymentTokenRequestBuilder::init( + PaymentTokenRequestPaymentSourceBuilder::init() + ->token(VaultTokenRequestBuilder::init(self::INVALID_ID, TokenRequestType::SETUP_TOKEN)->build()) + ->build() + )->build(), + 'payPalRequestId' => '', + ]; + // Perform API call + $result = self::$controller->paymentTokensCreate($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testSetupTokensGetWithStatus404() + { + // Perform API call + $result = self::$controller->setupTokensGet(self::NON_EXISTENT_SETUP_TOKEN_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testSetupTokensGetWithStatus400() + { + // Perform API call + $result = self::$controller->setupTokensGet(self::INVALID_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testPaymentTokensGetWithStatus404() + { + // Perform API call + $result = self::$controller->paymentTokensGet(self::NON_EXISTENT_PAYMENT_TOKEN_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testPaymentTokensGetWithStatus400() + { + // Perform API call + $result = self::$controller->paymentTokensGet(self::NON_EXISTENT_PAYMENT_TOKEN_ID); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testCustomerPaymentTokensGetWithStatus404() + { + // Parameters for the API call + $request = [ + 'customerId' => self::NON_EXISTENT_CUSTOMER_ID, + 'pageSize' => 5, + 'page' => 1, + 'totalRequired' => false, + ]; + // Perform API call + $result = self::$controller->customerPaymentTokensGet($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(404) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testCustomerPaymentTokensGetWithStatus400() + { + // Parameters for the API call + $request = [ + 'customerId' => self::INVALID_ID, + 'pageSize' => 5, + 'page' => 1, + 'totalRequired' => false, + ]; + // Perform API call + $result = self::$controller->customerPaymentTokensGet($request); + + $headers = []; + $headers['Content-Type'] = ['application/json', true]; + + // Assert result with expected response + $this->assertTrue($result->isError()); + $this->newTestCase($result->getResult()) + ->expectStatus(400) + ->allowExtraHeaders() + ->expectHeaders($headers) + ->assert(); + } + + public function testPaymentTokensDeleteWithStatus204() + { + // Perform API call + $result = self::$controller->paymentTokensDelete(self::NON_EXISTENT_PAYMENT_TOKEN_ID); + + // Assert result with expected response + $this->assertTrue($result->isSuccess()); + $this->newTestCase($result->getResult()) + ->expectStatus(204) + ->assert(); + } +} diff --git a/tests/WebDriverUtilities.php b/tests/WebDriverUtilities.php new file mode 100644 index 0000000..508efd3 --- /dev/null +++ b/tests/WebDriverUtilities.php @@ -0,0 +1,212 @@ +get($checkoutUrl); + + $elements = $driver->findElements(WebDriverBy::cssSelector('#email')); + if (count($elements) > 0) { + // If not logged in fill in the email + $emailField = $elements[0]; + $emailField->clear(); + $emailField->sendKeys($email); + + $elements = $driver->findElements(WebDriverBy::cssSelector('#btnNext')); + if (count($elements) > 0) { + // Click the Next button if found + $elements[0]->click(); + } + + // Wait for the login button + $driver->wait(50)->until( + WebDriverExpectedCondition::visibilityOfElementLocated( + WebDriverBy::cssSelector('#btnLogin') + ) + ); + + // Fill in password and login + $driver->findElement(WebDriverBy::cssSelector('#password'))->sendKeys($pass); + $driver->findElement(WebDriverBy::cssSelector('#btnLogin'))->click(); + } + + // Wait for the payment button + $driver->wait(50)->until( + WebDriverExpectedCondition::visibilityOfElementLocated( + WebDriverBy::cssSelector('#payment-submit-btn') + ) + ); + + // Click on payment submit button + $driver->findElement(WebDriverBy::cssSelector('#payment-submit-btn'))->click(); + + // Wait for the return URL + $driver->wait(50)->until( + WebDriverExpectedCondition::urlContains('https://example.com/returnUrl') + ); + } + + /** + * @throws Exception + */ + public static function savePaymentMethod(string $url): void + { + $email = getenv('EMAIL'); + $pass = getenv('PASSWORD'); + if (!isset($email) || !isset($pass)) { + throw new Exception('EMAIL or PASSWORD environment variable is not set'); + } + + $driver = self::getWebDriver(); + $driver->get($url); + + $elements = $driver->findElements(WebDriverBy::cssSelector('#email')); + if (count($elements) > 0) { + // If not logged in fill in the email + $emailField = $elements[0]; + $emailField->sendKeys($email); + + $elements = $driver->findElements(WebDriverBy::cssSelector('#btnNext')); + if (count($elements) > 0) { + // Click the Next button if found + $elements[0]->click(); + } + + // Wait for the login button + $driver->wait(50)->until( + WebDriverExpectedCondition::visibilityOfElementLocated( + WebDriverBy::cssSelector('#btnLogin') + ) + ); + + // Fill in password and login + $driver->findElement(WebDriverBy::cssSelector('#password'))->sendKeys($pass); + $driver->findElement(WebDriverBy::cssSelector('#btnLogin'))->click(); + } + + usleep(10 * 1000000); + + $elements = $driver->findElements(WebDriverBy::cssSelector('#consentButton')); + if (count($elements) > 0) { + // Click the Consent button if found + $elements[0]->click(); + } else { + // Go back to the previous page + $driver->navigate()->back(); + + // Wait for the consent button + $driver->wait(50)->until( + WebDriverExpectedCondition::visibilityOfElementLocated( + WebDriverBy::cssSelector('#consentButton') + ) + ); + + // Click on consent button + $driver->findElement(WebDriverBy::cssSelector('#consentButton'))->click(); + } + + // Wait for the return URL + $driver->wait(50)->until( + WebDriverExpectedCondition::urlContains('https://example.com/returnUrl') + ); + } + + /** + * @throws Exception + */ + public static function completeHeliosVerification(string $checkoutUrl): void + { + $driver = self::getWebDriver(); + $driver->get($checkoutUrl); + + // Wait for the specific PayPal verification URL + $driver->wait(50)->until( + WebDriverExpectedCondition::urlContains( + 'https://www.sandbox.paypal.com/webapps/helios?action=verify&flow=3ds' + ) + ); + + // Wait until the outer iframe loads completely + usleep(10 * 1000000); // wait 10 secs + + if (strpos($driver->getCurrentURL(), 'https://example.com/returnUrl') !== false) { + return; + } + + // Switch to the appropriate iframe + $frame = $driver->switchTo()->frame( + $driver->findElement(WebDriverBy::cssSelector('iframe[name="threedsIframeV2"]')) + ); + + $frame = $frame->switchTo()->frame( + $driver->findElement(WebDriverBy::tagName('iframe')) + ); + + // Enter the verification code and submit + $frame->findElement(WebDriverBy::cssSelector('input[placeholder=" Enter Code Here"]'))->sendKeys('1234'); + $submitButton = $frame->findElement(WebDriverBy::cssSelector('input[type="submit"][value="SUBMIT"]')); + $driver->executeScript('arguments[0].scrollIntoView(true);', [$submitButton]); + if ($submitButton->isDisplayed()) { + $submitButton->click(); + } + + // Check for the return URL + $driver->wait(50)->until( + WebDriverExpectedCondition::urlContains('https://example.com/returnUrl') + ); + } + + /** + * @var RemoteWebDriver + */ + private static $remoteWebDriver; + + /** + * @throws Exception + */ + private static function getWebDriver(int $tryCount = 3): RemoteWebDriver + { + if (!isset(self::$remoteWebDriver)) { + $options = new FirefoxOptions(); + $options->addArguments(['--headless']); + + $capabilities = DesiredCapabilities::firefox(); + $capabilities->setCapability(FirefoxOptions::CAPABILITY, $options); + + try { + self::$remoteWebDriver = RemoteWebDriver::create( + 'http://localhost:4444', + $capabilities, + 500000, + 500000 + ); + } catch (Exception $exp) { + if ($tryCount == 0) { + throw $exp; + } + return self::getWebDriver($tryCount - 1); + } + } + return self::$remoteWebDriver; + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..5ceb82d --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,18 @@ +