diff --git a/src/Components/ApplePayDirect/ApplePayDirect.php b/src/Components/ApplePayDirect/ApplePayDirect.php index 013768326..6247d3e35 100644 --- a/src/Components/ApplePayDirect/ApplePayDirect.php +++ b/src/Components/ApplePayDirect/ApplePayDirect.php @@ -2,7 +2,11 @@ namespace Kiener\MolliePayments\Components\ApplePayDirect; +use Kiener\MolliePayments\Components\ApplePayDirect\Exceptions\ApplePayDirectDomainAllowListCanNotBeEmptyException; +use Kiener\MolliePayments\Components\ApplePayDirect\Exceptions\ApplePayDirectDomainNotInAllowListException; +use Kiener\MolliePayments\Components\ApplePayDirect\Gateways\ApplePayDirectDomainAllowListGateway; use Kiener\MolliePayments\Components\ApplePayDirect\Models\ApplePayCart; +use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayDirectDomainSanitizer; use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayDomainVerificationService; use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayFormatter; use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayShippingBuilder; @@ -105,6 +109,16 @@ class ApplePayDirect */ private $repoOrderAdresses; + /** + * @var ApplePayDirectDomainAllowListGateway + */ + private $applePayDirectDomainAllowListGateway; + + /** + * @var ApplePayDirectDomainSanitizer + */ + private $domainSanitizer; + /** * @param ApplePayDomainVerificationService $domainFileDownloader @@ -121,8 +135,10 @@ class ApplePayDirect * @param ShopService $shopService * @param OrderService $orderService * @param OrderAddressRepositoryInterface $repoOrderAdresses + * @param ApplePayDirectDomainAllowListGateway $domainAllowListGateway + * @param ApplePayDirectDomainSanitizer $domainSanitizer */ - public function __construct(ApplePayDomainVerificationService $domainFileDownloader, ApplePayPayment $paymentHandler, MolliePaymentDoPay $molliePayments, CartServiceInterface $cartService, ApplePayFormatter $formatter, ApplePayShippingBuilder $shippingBuilder, SettingsService $pluginSettings, CustomerService $customerService, PaymentMethodRepository $repoPaymentMethods, CartBackupService $cartBackupService, MollieApiFactory $mollieApiFactory, ShopService $shopService, OrderService $orderService, OrderAddressRepositoryInterface $repoOrderAdresses) + public function __construct(ApplePayDomainVerificationService $domainFileDownloader, ApplePayPayment $paymentHandler, MolliePaymentDoPay $molliePayments, CartServiceInterface $cartService, ApplePayFormatter $formatter, ApplePayShippingBuilder $shippingBuilder, SettingsService $pluginSettings, CustomerService $customerService, PaymentMethodRepository $repoPaymentMethods, CartBackupService $cartBackupService, MollieApiFactory $mollieApiFactory, ShopService $shopService, OrderService $orderService, OrderAddressRepositoryInterface $repoOrderAdresses, ApplePayDirectDomainAllowListGateway $domainAllowListGateway, ApplePayDirectDomainSanitizer $domainSanitizer) { $this->domainFileDownloader = $domainFileDownloader; $this->paymentHandler = $paymentHandler; @@ -138,6 +154,8 @@ public function __construct(ApplePayDomainVerificationService $domainFileDownloa $this->shopService = $shopService; $this->orderService = $orderService; $this->repoOrderAdresses = $repoOrderAdresses; + $this->applePayDirectDomainAllowListGateway = $domainAllowListGateway; + $this->domainSanitizer = $domainSanitizer; } @@ -261,18 +279,16 @@ public function setShippingMethod(string $shippingMethodID, SalesChannelContext /** * @param string $validationURL + * @param string $domain * @param SalesChannelContext $context * @throws ApiException + * @throws ApplePayDirectDomainAllowListCanNotBeEmptyException + * @throws ApplePayDirectDomainNotInAllowListException * @return string */ - public function createPaymentSession(string $validationURL, SalesChannelContext $context): string + public function createPaymentSession(string $validationURL, string $domain, SalesChannelContext $context): string { - # make sure to get rid of any http prefixes or - # also any sub shop slugs like /de or anything else - # that would NOT work with Mollie and Apple Pay! - $domainExtractor = new DomainExtractor(); - $domain = $domainExtractor->getCleanDomain($this->shopService->getShopUrl(true)); - + $domain = $this->getValidDomain($domain, $context); # we always have to use the LIVE api key for # our first domain validation for Apple Pay! # the rest will be done with our test API key (if test mode active), or also Live API key (no test mode) @@ -507,4 +523,39 @@ private function buildApplePayCart(Cart $cart): ApplePayCart return $appleCart; } + + /** + * This method will return a valid domain if not provided by the user it will use the shop domain + * + * @param SalesChannelContext $context + * @param string $domain + * @throws ApplePayDirectDomainAllowListCanNotBeEmptyException + * @throws ApplePayDirectDomainNotInAllowListException + * @return string + */ + private function getValidDomain(string $domain, SalesChannelContext $context): string + { + # if we have no domain, then we need to use the shop domain + if (empty($domain)) { + # make sure to get rid of any http prefixes or + # also any sub shop slugs like /de or anything else + # that would NOT work with Mollie and Apple Pay! + $domainExtractor = new DomainExtractor(); + return $domainExtractor->getCleanDomain($this->shopService->getShopUrl(true)); + } + + $allowList = $this->applePayDirectDomainAllowListGateway->getAllowList($context); + + if ($allowList->isEmpty()) { + throw new ApplePayDirectDomainAllowListCanNotBeEmptyException(); + } + + $sanitizedDomain = $this->domainSanitizer->sanitizeDomain($domain); + + if ($allowList->contains($sanitizedDomain) === false) { + throw new ApplePayDirectDomainNotInAllowListException($sanitizedDomain); + } + + return $sanitizedDomain; + } } diff --git a/src/Components/ApplePayDirect/Exceptions/ApplePayDirectDomainAllowListCanNotBeEmptyException.php b/src/Components/ApplePayDirect/Exceptions/ApplePayDirectDomainAllowListCanNotBeEmptyException.php new file mode 100644 index 000000000..8dd5fdc30 --- /dev/null +++ b/src/Components/ApplePayDirect/Exceptions/ApplePayDirectDomainAllowListCanNotBeEmptyException.php @@ -0,0 +1,12 @@ +settingsService = $settingsService; + } + + /** + * Get the ApplePayDirectDomainAllowList + * + * @param SalesChannelContext $context + * @return ApplePayDirectDomainAllowList + */ + public function getAllowList(SalesChannelContext $context): ApplePayDirectDomainAllowList + { + $settings = $this->settingsService->getSettings($context->getSalesChannel()->getId()); + $allowList = $settings->getApplePayDirectDomainAllowList(); + + if (empty($allowList)) { + return ApplePayDirectDomainAllowList::create(); + } + + $allowList = trim($allowList); + + $items = explode(',', $allowList); + $items = array_map([ApplePayDirectDomainAllowListItem::class, 'create'], $items); + + return ApplePayDirectDomainAllowList::create(...$items); + } +} diff --git a/src/Components/ApplePayDirect/Models/ApplePayDirectDomainAllowListItem.php b/src/Components/ApplePayDirect/Models/ApplePayDirectDomainAllowListItem.php new file mode 100644 index 000000000..d86860abd --- /dev/null +++ b/src/Components/ApplePayDirect/Models/ApplePayDirectDomainAllowListItem.php @@ -0,0 +1,52 @@ +value = $value; + } + + /** + * Create a new ApplePayDirectDomainAllowListItem + * + * @param string $value + * @return self + */ + public static function create(string $value): self + { + if (empty($value)) { + throw new \InvalidArgumentException(sprintf('The value of %s must not be empty', self::class)); + } + + $value = (new ApplePayDirectDomainSanitizer())->sanitizeDomain($value); + + return new self($value); + } + + /** + * Compare the value with the given value + * + * @param string $value value that will be compared + * @return bool + */ + public function equals(string $value): bool + { + return $this->value === $value; + } +} diff --git a/src/Components/ApplePayDirect/Models/Collections/ApplePayDirectDomainAllowList.php b/src/Components/ApplePayDirect/Models/Collections/ApplePayDirectDomainAllowList.php new file mode 100644 index 000000000..28a0a4f03 --- /dev/null +++ b/src/Components/ApplePayDirect/Models/Collections/ApplePayDirectDomainAllowList.php @@ -0,0 +1,69 @@ +allowList = $allowList; + } + + /** + * Create a new ApplePayDirectDomainAllowList + * + * @param ApplePayDirectDomainAllowListItem ...$items + * @return ApplePayDirectDomainAllowList + */ + public static function create(ApplePayDirectDomainAllowListItem ...$items): self + { + return new self($items); + } + + /** + * Check if the given value is in the allow list + * + * @param string $value + * @return bool + */ + public function contains(string $value): bool + { + foreach ($this->allowList as $item) { + if ($item->equals($value)) { + return true; + } + } + + return false; + } + + /** + * @return bool + */ + public function isEmpty(): bool + { + return count($this) === 0; + } + + /** + * @inheritDoc + */ + public function count(): int + { + return count($this->allowList); + } +} diff --git a/src/Components/ApplePayDirect/Services/ApplePayDirectDomainSanitizer.php b/src/Components/ApplePayDirect/Services/ApplePayDirectDomainSanitizer.php new file mode 100644 index 000000000..f76aa4338 --- /dev/null +++ b/src/Components/ApplePayDirect/Services/ApplePayDirectDomainSanitizer.php @@ -0,0 +1,29 @@ +get('validationUrl'); + $domain = (string)$data->get('domain'); if (empty($validationURL)) { throw new \Exception('Please provide a validation url!'); } - $session = $this->applePay->createPaymentSession($validationURL, $context); + $session = $this->applePay->createPaymentSession($validationURL, $domain, $context); return new CreateSessionResponse($session); } diff --git a/src/Controller/Storefront/ApplePayDirect/ApplePayDirectControllerBase.php b/src/Controller/Storefront/ApplePayDirect/ApplePayDirectControllerBase.php index 88815a052..a892125fc 100644 --- a/src/Controller/Storefront/ApplePayDirect/ApplePayDirectControllerBase.php +++ b/src/Controller/Storefront/ApplePayDirect/ApplePayDirectControllerBase.php @@ -221,7 +221,7 @@ public function createPaymentSession(SalesChannelContext $context, Request $requ $validationURL = (string)$content['validationUrl']; - $session = $this->applePay->createPaymentSession($validationURL, $context); + $session = $this->applePay->createPaymentSession($validationURL, '', $context); return new JsonResponse([ 'session' => $session, diff --git a/src/Resources/config/config.xml b/src/Resources/config/config.xml index 2184638f7..e43e72307 100644 --- a/src/Resources/config/config.xml +++ b/src/Resources/config/config.xml @@ -152,6 +152,28 @@ + + applePayDirectDomainAllowList + + + + + Enter the domains that are allowed for Apple Pay Direct, separated by commas. + This setting is optional and only required if you are using a headless setup + and want to provide an alternative domain for your Apple Pay Direct integration. + + + Geben Sie die Domains ein, die für die Apple Pay Direct zugelassen sind, getrennt durch Kommas. + Diese Einstellung ist optional und nur erforderlich, wenn Sie ein Headless-Setup verwenden + und eine alternative Domain für Ihre Apple Pay Direct Integration bereitstellen möchten. + + + Voer de domeinen in die zijn toegestaan voor Apple Pay Direct, gescheiden door komma's. + Deze instelling is optioneel en alleen nodig als u een headless setup gebruikt + en een alternatieve domein voor uw Apple Pay Direct integratie wilt opgeven. + + + createCustomersAtMollie diff --git a/src/Resources/config/services/components.xml b/src/Resources/config/services/components.xml index 2d20b69df..d07d1c43a 100644 --- a/src/Resources/config/services/components.xml +++ b/src/Resources/config/services/components.xml @@ -5,6 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + @@ -39,6 +40,8 @@ + + @@ -47,6 +50,13 @@ + + + + + + + diff --git a/src/Setting/MollieSettingStruct.php b/src/Setting/MollieSettingStruct.php index 583f2e594..97c7078d7 100644 --- a/src/Setting/MollieSettingStruct.php +++ b/src/Setting/MollieSettingStruct.php @@ -15,6 +15,8 @@ class MollieSettingStruct extends Struct public const ORDER_EXPIRES_AT_MIN_DAYS = 1; public const ORDER_EXPIRES_AT_MAX_DAYS = 100; + const APPLE_PAY_DIRECT_DOMAIN_ALLOW_LIST = 'applePayDirectDomainAllowList'; + /** * @var string */ @@ -248,6 +250,11 @@ class MollieSettingStruct extends Struct */ protected $phoneNumberFieldRequired = false; + /** + * @var string + */ + protected $applePayDirectDomainAllowList = ''; + /** * @return string */ @@ -965,4 +972,14 @@ public function setPhoneNumberFieldRequired(bool $phoneNumberFieldRequired): voi { $this->phoneNumberFieldRequired = $phoneNumberFieldRequired; } + + public function getApplePayDirectDomainAllowList(): string + { + return $this->applePayDirectDomainAllowList; + } + + public function setApplePayDirectDomainAllowList(string $applePayDirectDomainAllowList): void + { + $this->applePayDirectDomainAllowList = $applePayDirectDomainAllowList; + } } diff --git a/tests/PHPUnit/Components/ApplePayDirect/Gateways/ApplePayDirectDomainAllowListGatewayTest.php b/tests/PHPUnit/Components/ApplePayDirect/Gateways/ApplePayDirectDomainAllowListGatewayTest.php new file mode 100644 index 000000000..2e98db0a2 --- /dev/null +++ b/tests/PHPUnit/Components/ApplePayDirect/Gateways/ApplePayDirectDomainAllowListGatewayTest.php @@ -0,0 +1,67 @@ +service = $this->createMock(SettingsService::class); + $this->gateway = new ApplePayDirectDomainAllowListGateway($this->service); + $this->scContext = $this->createConfiguredMock(SalesChannelContext::class, [ + 'getContext' => $this->context = $this->createMock(Context::class), + ]); + } + + public function testProvidesEmptyAllowList(): void + { + $struct = $this->createConfiguredMock(MollieSettingStruct::class, ['getApplePayDirectDomainAllowList' => '']); + $this->service->expects($this->once())->method('getSettings')->willReturn($struct); + $allowList = $this->gateway->getAllowList($this->scContext); + + $this->assertTrue($allowList->isEmpty()); + } + + public function testProvidesAllowList(): void + { + $allowListString = 'https://example.com,https://example-url.org'; + $struct = $this->createConfiguredMock(MollieSettingStruct::class, ['getApplePayDirectDomainAllowList' => $allowListString]); + $this->service->expects($this->once())->method('getSettings')->willReturn($struct); + + $allowList = $this->gateway->getAllowList($this->scContext); + + $this->assertFalse($allowList->isEmpty()); + $this->assertCount(2, $allowList); + } +} \ No newline at end of file diff --git a/tests/PHPUnit/Components/ApplePayDirect/Models/Collections/ApplePayDirectDomainAllowListTest.php b/tests/PHPUnit/Components/ApplePayDirect/Models/Collections/ApplePayDirectDomainAllowListTest.php new file mode 100644 index 000000000..cdc8eb82a --- /dev/null +++ b/tests/PHPUnit/Components/ApplePayDirect/Models/Collections/ApplePayDirectDomainAllowListTest.php @@ -0,0 +1,41 @@ +assertTrue($allowList->contains('example.com')); + $this->assertTrue($allowList->contains('example-url.org')); + $this->assertFalse($allowList->contains('example-url.net')); + } + + public function testCanDetermineIfListIsEmpty(): void + { + $allowList = ApplePayDirectDomainAllowList::create(); + + $this->assertTrue($allowList->isEmpty()); + } + + public function testProvidesCount(): void + { + $allowList = ApplePayDirectDomainAllowList::create( + ApplePayDirectDomainAllowListItem::create('example.com'), + ApplePayDirectDomainAllowListItem::create('example-url.org') + ); + + $this->assertCount(2, $allowList); + } +} \ No newline at end of file diff --git a/tests/PHPUnit/Components/ApplePayDirect/Services/ApplePayDirectDomainSanitizerTest.php b/tests/PHPUnit/Components/ApplePayDirect/Services/ApplePayDirectDomainSanitizerTest.php new file mode 100644 index 000000000..f6bccbdb5 --- /dev/null +++ b/tests/PHPUnit/Components/ApplePayDirect/Services/ApplePayDirectDomainSanitizerTest.php @@ -0,0 +1,40 @@ +sanitizer = new ApplePayDirectDomainSanitizer(); + } + + /** + * @dataProvider sanitationTestDataProvider + */ + public function testProvidesSanitizedDomain(string $url, string $expected): void + { + $sanitizedUrl = $this->sanitizer->sanitizeDomain($url); + + $this->assertEquals($expected, $sanitizedUrl); + } + + public function sanitationTestDataProvider(): array + { + return [ + 'removes http value if provided' => ['http://example.com', 'example.com'], + 'removes https value if provided' => ['https://example.com', 'example.com'], + 'removes trailing slash if provided' => ['https://example.com/', 'example.com'], + 'removes https at beginning of string and trailing slash if provided' => ['https://example.com/', 'example.com'], + 'removes shop language slug if provided' => ['https://example.com/shop/de', 'example.com'], + 'removes shop language slug and trailing slash if provided' => ['example.com/shop/de/', 'example.com'], + 'removes shop language slug and trailing slash if provided and protocol' => ['https://example.com/shop/de/', 'example.com'], + 'sub domains are not removed' => ['sub.example.com', 'sub.example.com'], + ]; + } +} \ No newline at end of file diff --git a/tests/PHPUnit/Service/ApplePayDirect/ApplePayDirectTest.php b/tests/PHPUnit/Service/ApplePayDirect/ApplePayDirectTest.php index 45fbc9fe1..1ba026b41 100644 --- a/tests/PHPUnit/Service/ApplePayDirect/ApplePayDirectTest.php +++ b/tests/PHPUnit/Service/ApplePayDirect/ApplePayDirectTest.php @@ -3,9 +3,15 @@ namespace Kiener\MolliePayments\Tests\Service\ApplePayDirect; use Kiener\MolliePayments\Components\ApplePayDirect\ApplePayDirect; +use Kiener\MolliePayments\Components\ApplePayDirect\Exceptions\ApplePayDirectDomainAllowListCanNotBeEmptyException; +use Kiener\MolliePayments\Components\ApplePayDirect\Exceptions\ApplePayDirectDomainNotInAllowListException; +use Kiener\MolliePayments\Components\ApplePayDirect\Gateways\ApplePayDirectDomainAllowListGateway; +use Kiener\MolliePayments\Components\ApplePayDirect\Models\ApplePayDirectDomainAllowListItem; +use Kiener\MolliePayments\Components\ApplePayDirect\Models\Collections\ApplePayDirectDomainAllowList; use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayDomainVerificationService; use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayFormatter; use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayShippingBuilder; +use Kiener\MolliePayments\Components\ApplePayDirect\Services\ApplePayDirectDomainSanitizer; use Kiener\MolliePayments\Facade\MolliePaymentDoPay; use Kiener\MolliePayments\Factory\MollieApiFactory; use Kiener\MolliePayments\Handler\Method\ApplePayPayment; @@ -17,8 +23,11 @@ use Kiener\MolliePayments\Service\SettingsService; use Kiener\MolliePayments\Service\ShippingMethodService; use Kiener\MolliePayments\Service\ShopService; +use Mollie\Api\Endpoints\WalletEndpoint; +use Mollie\Api\MollieApiClient; use MolliePayments\Tests\Fakes\FakeCartService; use MolliePayments\Tests\Traits\MockTrait; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Shopware\Core\Checkout\Cart\Cart; use Shopware\Core\Checkout\Cart\Delivery\Struct\Delivery; @@ -41,22 +50,23 @@ class ApplePayDirectTest extends TestCase { use MockTrait; + private SalesChannelContext $scContext; + + private $validationUrlAllowListGateway; + private ApplePayDirect $applePay; + /** - * This test verifies that our Apple Pay Cart is correctly - * built from a provided Shopware Cart object. + * @var MollieApiFactory|\PHPUnit\Framework\MockObject\MockObject */ - public function testBuildApplePayCart(): void + private $apiFactory; + + protected function setUp(): void { $swCart = $this->buildShopwareCart(); - /** @var SalesChannelContext $scContext */ - $scContext = $this->createDummyMock(SalesChannelContext::class, $this); - + $this->scContext = $this->createDummyMock(SalesChannelContext::class, $this); - $fakeCartService = new FakeCartService($swCart, $scContext); - - /** @var ShippingMethodService $shippingMethodService */ - $shippingMethodService = $this->createDummyMock(ShippingMethodService::class, $this); + $fakeCartService = new FakeCartService($swCart, $this->scContext); /** @var ApplePayDomainVerificationService $domainVerification */ $domainVerification = $this->createDummyMock(ApplePayDomainVerificationService::class, $this); @@ -86,7 +96,7 @@ public function testBuildApplePayCart(): void $cartBackupService = $this->createDummyMock(CartBackupService::class, $this); /** @var MollieApiFactory $apiFactory */ - $apiFactory = $this->createDummyMock(MollieApiFactory::class, $this); + $this->apiFactory = $this->createDummyMock(MollieApiFactory::class, $this); /** @var ShopService $shopService */ $shopService = $this->createDummyMock(ShopService::class, $this); @@ -97,8 +107,11 @@ public function testBuildApplePayCart(): void /** @var OrderAddressRepository $repoOrderAdresses */ $repoOrderAdresses = $this->createDummyMock(OrderAddressRepository::class, $this); + $this->validationUrlAllowListGateway = $this->createDummyMock(ApplePayDirectDomainAllowListGateway::class, $this); + + $validationUrlSanitizer = new ApplePayDirectDomainSanitizer(); - $applePay = new ApplePayDirect( + $this->applePay = new ApplePayDirect( $domainVerification, $payment, $doPay, @@ -109,13 +122,22 @@ public function testBuildApplePayCart(): void $customerService, $repoPaymentMethods, $cartBackupService, - $apiFactory, + $this->apiFactory, $shopService, $orderService, - $repoOrderAdresses + $repoOrderAdresses, + $this->validationUrlAllowListGateway, + $validationUrlSanitizer ); + } - $apCart = $applePay->getCart($scContext); + /** + * This test verifies that our Apple Pay Cart is correctly + * built from a provided Shopware Cart object. + */ + public function testBuildApplePayCart(): void + { + $apCart = $this->applePay->getCart($this->scContext); $this->assertEquals(34.99, $apCart->getAmount()); $this->assertEquals(5, $apCart->getTaxes()->getPrice()); @@ -131,6 +153,58 @@ public function testBuildApplePayCart(): void $this->assertEquals(1, $apCart->getShippings()[0]->getQuantity()); } + public function testThrowsExceptionWhenAllowListIsEmptyWhileTryingToCreatePaymentSession(): void + { + $this->validationUrlAllowListGateway->expects($this->once()) + ->method('getAllowList') + ->willReturn(ApplePayDirectDomainAllowList::create()); + + $this->expectException(ApplePayDirectDomainAllowListCanNotBeEmptyException::class); + $this->expectExceptionMessage('The Apple Pay Direct domain allow list can not be empty. Please check the configuration.'); + + $this->applePay->createPaymentSession('https://example.com', 'example.com', $this->scContext); + } + + public function testThrowsExceptionWhenUrlIsNotInAllowListWhileTryingToCreatePaymentSession(): void + { + $allowList = ApplePayDirectDomainAllowList::create( + ApplePayDirectDomainAllowListItem::create('example.com') + ); + $this->validationUrlAllowListGateway->expects($this->once()) + ->method('getAllowList') + ->willReturn($allowList); + + $testDomain = 'example.org'; + + $this->expectException(ApplePayDirectDomainNotInAllowListException::class); + $this->expectExceptionMessage(sprintf('The given URL %s is not in the Apple Pay Direct domain allow list.', $testDomain)); + + $this->applePay->createPaymentSession('https://example.org', $testDomain, $this->scContext); + } + + public function testCanCreatePaymentSession(): void + { + $allowList = ApplePayDirectDomainAllowList::create( + ApplePayDirectDomainAllowListItem::create($domain = 'example.com') + ); + + $this->validationUrlAllowListGateway->expects($this->once()) + ->method('getAllowList') + ->willReturn($allowList); + + $client = $this->createMock(MollieApiClient::class); + $client->wallets = $this->createMock(WalletEndpoint::class); + $this->apiFactory->expects($this->once()) + ->method('getLiveClient') + ->willReturn($client); + + $client->wallets->expects($this->once())->method('requestApplePayPaymentSession') + ->willReturn($expected = random_bytes(16)); + + $actual = $this->applePay->createPaymentSession('https://example.com', $domain, $this->scContext); + + $this->assertSame($expected, $actual); + } /** * @return Cart