diff --git a/features/checkout/addressing_order/returning_to_addressing_step_with_a_different_shipping_address.feature b/features/checkout/addressing_order/returning_to_addressing_step_with_a_different_shipping_address.feature new file mode 100644 index 0000000000..d84f6e2e49 --- /dev/null +++ b/features/checkout/addressing_order/returning_to_addressing_step_with_a_different_shipping_address.feature @@ -0,0 +1,52 @@ +@checkout +Feature: Returning to addressing step with a different shipping address + In order to change the shipping address + As a Visitor + I want to return to the addressing step and change the shipping address + + Background: + Given the store operates on a single channel in "United States" + And the store has a product "Summer T-Shirt" priced at "$19.99" + And the store ships everywhere for free + + @ui + Scenario: Going back to addressing step after submitting a different shipping address + Given I have product "Summer T-Shirt" in the cart + And I am at the checkout addressing step + When I specify the email as "john.doe@example.com" + And I specify the billing address as "Brooklyn", "9036 Country Club Ave.", "11230", "United States" for "John Doe" + And I specify the shipping address as "Brooklyn", "70 Joy Ridge St", "11225", "United States" for "Jane Doe" + And I complete the addressing step + And I decide to change my address + Then different shipping address should be checked + + @ui + Scenario: Going back to addressing step after not submitting a different shipping address + Given I have product "Summer T-Shirt" in the cart + And I am at the checkout addressing step + When I specify the email as "john.doe@example.com" + And I specify the billing address as "Brooklyn", "9036 Country Club Ave.", "11230", "United States" for "John Doe" + And I complete the addressing step + And I decide to change my address + Then different shipping address should not be checked + + @ui @javascript + Scenario: Going back to addressing step after submitting a different shipping address + Given I have product "Summer T-Shirt" in the cart + And I am at the checkout addressing step + When I specify the email as "john.doe@example.com" + And I specify the billing address as "Brooklyn", "9036 Country Club Ave.", "11230", "United States" for "John Doe" + And I specify the shipping address as "Brooklyn", "70 Joy Ridge St", "11225", "United States" for "Jane Doe" + And I complete the addressing step + And I decide to change my address + And shipping address should be visible + + @ui @javascript + Scenario: Going back to addressing step after not submitting a different shipping address + Given I have product "Summer T-Shirt" in the cart + And I am at the checkout addressing step + When I specify the email as "john.doe@example.com" + And I specify the billing address as "Brooklyn", "9036 Country Club Ave.", "11230", "United States" for "John Doe" + And I complete the addressing step + And I decide to change my address + And shipping address should not be visible diff --git a/src/Sylius/Behat/Context/Ui/Shop/Checkout/CheckoutAddressingContext.php b/src/Sylius/Behat/Context/Ui/Shop/Checkout/CheckoutAddressingContext.php index d6c9e454a9..4b524b13d5 100644 --- a/src/Sylius/Behat/Context/Ui/Shop/Checkout/CheckoutAddressingContext.php +++ b/src/Sylius/Behat/Context/Ui/Shop/Checkout/CheckoutAddressingContext.php @@ -377,6 +377,38 @@ final class CheckoutAddressingContext implements Context Assert::true($this->addressComparator->equal($address, $this->addressPage->getPreFilledBillingAddress())); } + /** + * @Then different shipping address should be checked + */ + public function differentShippingAddressShouldBeChecked(): void + { + Assert::true($this->addressPage->isDifferentShippingAddressChecked()); + } + + /** + * @Then different shipping address should not be checked + */ + public function differentShippingAddressShouldNotBeChecked(): void + { + Assert::false($this->addressPage->isDifferentShippingAddressChecked()); + } + + /** + * @Then shipping address should be visible + */ + public function shippingAddressShouldBeVisible(): void + { + Assert::true($this->addressPage->isShippingAddressVisible()); + } + + /** + * @Then shipping address should not be visible + */ + public function shippingAddressShouldNotBeVisible(): void + { + Assert::false($this->addressPage->isShippingAddressVisible()); + } + /** * @Then /^I should(?:| also) be notified that the "([^"]+)" and the "([^"]+)" in (shipping|billing) details are required$/ */ diff --git a/src/Sylius/Behat/Page/Shop/Checkout/AddressPage.php b/src/Sylius/Behat/Page/Shop/Checkout/AddressPage.php index ba88316674..2278fda38a 100644 --- a/src/Sylius/Behat/Page/Shop/Checkout/AddressPage.php +++ b/src/Sylius/Behat/Page/Shop/Checkout/AddressPage.php @@ -16,6 +16,7 @@ namespace Sylius\Behat\Page\Shop\Checkout; use Behat\Mink\Driver\Selenium2Driver; use Behat\Mink\Element\NodeElement; use Behat\Mink\Exception\ElementNotFoundException; +use Behat\Mink\Exception\UnsupportedDriverActionException; use Behat\Mink\Session; use DMore\ChromeDriver\ChromeDriver; use FriendsOfBehat\PageObjectExtension\Page\SymfonyPage; @@ -68,6 +69,21 @@ class AddressPage extends SymfonyPage implements AddressPageInterface $billingAddressSwitch->check(); } + public function isDifferentShippingAddressChecked(): bool + { + return $this->getElement('different_shipping_address')->isChecked(); + } + + public function isShippingAddressVisible(): bool + { + try { + return $this->getElement('shipping_address')->isVisible(); + } catch (UnsupportedDriverActionException $e) { + // it's visible by default and is being hidden with JS + return true; + } + } + public function checkInvalidCredentialsValidation(): bool { /** @var NodeElement $validationElement */ @@ -285,6 +301,7 @@ class AddressPage extends SymfonyPage implements AddressPageInterface 'login_password' => '[data-test-password-input]', 'login_validation_error' => '[data-test-login-validation-error]', 'next_step' => '[data-test-next-step]', + 'shipping_address' => '[data-test-shipping-address]', 'shipping_address_book' => '[data-test-shipping-address] [data-test-address-book]', 'shipping_city' => '[data-test-shipping-city]', 'shipping_country' => '[data-test-shipping-country]', diff --git a/src/Sylius/Behat/Page/Shop/Checkout/AddressPageInterface.php b/src/Sylius/Behat/Page/Shop/Checkout/AddressPageInterface.php index 34e4a8c790..130319e62d 100644 --- a/src/Sylius/Behat/Page/Shop/Checkout/AddressPageInterface.php +++ b/src/Sylius/Behat/Page/Shop/Checkout/AddressPageInterface.php @@ -71,4 +71,8 @@ interface AddressPageInterface extends SymfonyPageInterface /** @return string[] */ public function getAvailableBillingCountries(): array; + + public function isDifferentShippingAddressChecked(): bool; + + public function isShippingAddressVisible(): bool; } diff --git a/src/Sylius/Bundle/CoreBundle/Form/Type/Checkout/AddressType.php b/src/Sylius/Bundle/CoreBundle/Form/Type/Checkout/AddressType.php index a6db4e84d9..49e8a2a6c5 100644 --- a/src/Sylius/Bundle/CoreBundle/Form/Type/Checkout/AddressType.php +++ b/src/Sylius/Bundle/CoreBundle/Form/Type/Checkout/AddressType.php @@ -16,6 +16,8 @@ namespace Sylius\Bundle\CoreBundle\Form\Type\Checkout; use Sylius\Bundle\AddressingBundle\Form\Type\AddressType as SyliusAddressType; use Sylius\Bundle\CoreBundle\Form\Type\Customer\CustomerCheckoutGuestType; use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType; +use Sylius\Component\Addressing\Comparator\AddressComparatorInterface; +use Sylius\Component\Core\Model\AddressInterface; use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Customer\Model\CustomerAwareInterface; @@ -29,6 +31,29 @@ use Webmozart\Assert\Assert; final class AddressType extends AbstractResourceType { + /** @var AddressComparatorInterface|null */ + private $addressComparator; + + public function __construct(string $dataClass, array $validationGroups = [], ?AddressComparatorInterface $addressComparator = null) + { + parent::__construct($dataClass, $validationGroups); + + if (null === $addressComparator) { + @trigger_error( + sprintf( + 'Not passing an $addressComparator to "%s" constructor is deprecated since Sylius 1.8 and will be impossible in Sylius 2.0.', + __CLASS__, + ), + \E_USER_DEPRECATED + ); + } + + $this->addressComparator = $addressComparator; + } + + /** + * {@inheritdoc} + */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder @@ -44,11 +69,11 @@ final class AddressType extends AbstractResourceType ]) ->addEventListener(FormEvents::PRE_SET_DATA, static function (FormEvent $event): void { $form = $event->getForm(); - $order = $event->getData(); + + Assert::isInstanceOf($event->getData(), OrderInterface::class); /** @var OrderInterface $order */ - Assert::isInstanceOf($order, OrderInterface::class); - + $order = $event->getData(); $channel = $order->getChannel(); $form @@ -63,6 +88,18 @@ final class AddressType extends AbstractResourceType ]) ; }) + ->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event): void { + $form = $event->getForm(); + + Assert::isInstanceOf($event->getData(), OrderInterface::class); + + /** @var OrderInterface $order */ + $order = $event->getData(); + $areAddressesDifferent = $this->areAddressesDifferent($order->getBillingAddress(), $order->getShippingAddress()); + + $form->get('differentBillingAddress')->setData($areAddressesDifferent); + $form->get('differentShippingAddress')->setData($areAddressesDifferent); + }) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options): void { $form = $event->getForm(); $resource = $event->getData(); @@ -114,4 +151,13 @@ final class AddressType extends AbstractResourceType { return 'sylius_checkout_address'; } + + private function areAddressesDifferent(?AddressInterface $firstAddress, ?AddressInterface $secondAddress): bool + { + if (null === $this->addressComparator || null === $firstAddress || null === $secondAddress) { + return false; + } + + return !$this->addressComparator->equal($firstAddress, $secondAddress); + } } diff --git a/src/Sylius/Bundle/CoreBundle/Resources/config/services/checkout.xml b/src/Sylius/Bundle/CoreBundle/Resources/config/services/checkout.xml index c89ae5768e..650eb100d6 100644 --- a/src/Sylius/Bundle/CoreBundle/Resources/config/services/checkout.xml +++ b/src/Sylius/Bundle/CoreBundle/Resources/config/services/checkout.xml @@ -39,6 +39,7 @@ %sylius.model.order.class% %sylius.form.type.checkout_address.validation_groups% +