From a15f33557d72d4ab05a99e9583fbfc0e2daa2ba2 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Sun, 15 Sep 2019 16:12:58 -0400 Subject: [PATCH 01/43] Fix for the issue #24547 --- .../Customer/Model/Account/Redirect.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) mode change 100644 => 100755 app/code/Magento/Customer/Model/Account/Redirect.php diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php old mode 100644 new mode 100755 index 2ccaaea45680c..b9a669b8ba990 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -9,6 +9,7 @@ use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; use Magento\Framework\Url\HostChecker; use Magento\Framework\UrlInterface; use Magento\Store\Model\ScopeInterface; @@ -69,6 +70,11 @@ class Redirect */ protected $cookieManager; + /** + * @var CookieMetadataFactory + */ + protected $cookieMetadataFactory; + /** * @var HostChecker */ @@ -88,6 +94,7 @@ class Redirect * @param DecoderInterface $urlDecoder * @param CustomerUrl $customerUrl * @param ResultFactory $resultFactory + * @param CookieMetadataFactory $cookieMetadataFactory * @param HostChecker|null $hostChecker */ public function __construct( @@ -99,6 +106,7 @@ public function __construct( DecoderInterface $urlDecoder, CustomerUrl $customerUrl, ResultFactory $resultFactory, + CookieMetadataFactory $cookieMetadataFactory, HostChecker $hostChecker = null ) { $this->request = $request; @@ -109,6 +117,7 @@ public function __construct( $this->urlDecoder = $urlDecoder; $this->customerUrl = $customerUrl; $this->resultFactory = $resultFactory; + $this->cookieMetadataFactory = $cookieMetadataFactory; $this->hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); } @@ -279,7 +288,11 @@ public function getRedirectCookie() */ public function setRedirectCookie($route) { - $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route); + $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setHttpOnly(true) + ->setDuration(3600) + ->setPath($this->storeManager->getStore()->getStorePath()); + $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route, $cookieMetadata); } /** @@ -289,6 +302,8 @@ public function setRedirectCookie($route) */ public function clearRedirectCookie() { - $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL); + $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setPath($this->storeManager->getStore()->getStorePath()); + $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL, $cookieMetadata); } } From 664056fc0e4fedc5c10aac2d14537b285dbefffd Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Wed, 18 Sep 2019 11:17:21 -0400 Subject: [PATCH 02/43] Fix for the issue #24547 Magento\Customer\Model\Account\Redirect::setRedirectCookie() not properly working --- .../Api/RedirectCookieManagerInterface.php | 41 +++++++++++ .../Customer/Model/Account/Redirect.php | 27 ++++--- .../Customer/Model/RedirectCookieManager.php | 72 +++++++++++++++++++ .../Test/Unit/Model/Account/RedirectTest.php | 11 +++ app/code/Magento/Customer/etc/di.xml | 3 + 5 files changed, 139 insertions(+), 15 deletions(-) create mode 100755 app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php create mode 100755 app/code/Magento/Customer/Model/RedirectCookieManager.php mode change 100644 => 100755 app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php mode change 100644 => 100755 app/code/Magento/Customer/etc/di.xml diff --git a/app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php b/app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php new file mode 100755 index 0000000000000..5f4f1f6f917de --- /dev/null +++ b/app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php @@ -0,0 +1,41 @@ +request = $request; @@ -117,7 +120,7 @@ public function __construct( $this->urlDecoder = $urlDecoder; $this->customerUrl = $customerUrl; $this->resultFactory = $resultFactory; - $this->cookieMetadataFactory = $cookieMetadataFactory; + $this->redirectCookieManager = $redirectCookieManager; $this->hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); } @@ -277,7 +280,7 @@ public function setCookieManager($value) */ public function getRedirectCookie() { - return $this->getCookieManager()->getCookie(self::LOGIN_REDIRECT_URL, null); + return $this->redirectCookieManager->getRedirectCookie(); } /** @@ -288,11 +291,7 @@ public function getRedirectCookie() */ public function setRedirectCookie($route) { - $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() - ->setHttpOnly(true) - ->setDuration(3600) - ->setPath($this->storeManager->getStore()->getStorePath()); - $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route, $cookieMetadata); + $this->redirectCookieManager->setRedirectCookie($route, $this->storeManager->getStore()); } /** @@ -302,8 +301,6 @@ public function setRedirectCookie($route) */ public function clearRedirectCookie() { - $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() - ->setPath($this->storeManager->getStore()->getStorePath()); - $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL, $cookieMetadata); + $this->redirectCookieManager->clearRedirectCookie($this->storeManager->getStore()); } } diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php new file mode 100755 index 0000000000000..04c87717fe215 --- /dev/null +++ b/app/code/Magento/Customer/Model/RedirectCookieManager.php @@ -0,0 +1,72 @@ +cookieMetadataFactory = $cookieMetadataFactory; + $this->cookieManager = $cookieManager; + } + + /** + * {@inheritdoc} + */ + public function getRedirectCookie() + { + return $this->cookieManager->getCookie(self::COOKIE_NAME, null); + } + + /** + * {@inheritdoc} + */ + public function setRedirectCookie($route, StoreInterface $store) + { + $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setHttpOnly(true) + ->setDuration(3600) + ->setPath($store->getStorePath()); + $this->cookieManager->setPublicCookie(self::COOKIE_NAME, $route, $cookieMetadata); + } + + /** + * {@inheritdoc} + */ + public function clearRedirectCookie(StoreInterface $store) + { + $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setPath($store->getStorePath()); + $this->cookieManager->deleteCookie(self::COOKIE_NAME, $cookieMetadata); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php old mode 100644 new mode 100755 index 0138c6c709b7c..66971bc15d88f --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -8,6 +8,7 @@ namespace Magento\Customer\Test\Unit\Model\Account; +use Magento\Customer\Api\RedirectCookieManagerInterface; use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; @@ -80,6 +81,11 @@ class RedirectTest extends \PHPUnit\Framework\TestCase */ protected $resultFactory; + /** + * @var RedirectCookieManagerInterface | \PHPUnit_Framework_MockObject_MockObject + */ + protected $redirectCookieManager; + /** * @var HostChecker | \PHPUnit_Framework_MockObject_MockObject */ @@ -139,6 +145,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $this->redirectCookieManager = $this->getMockBuilder(RedirectCookieManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->hostChecker = $this->getMockBuilder(HostChecker::class) ->disableOriginalConstructor() ->getMock(); @@ -155,6 +165,7 @@ protected function setUp() 'urlDecoder' => $this->urlDecoder, 'customerUrl' => $this->customerUrl, 'resultFactory' => $this->resultFactory, + 'redirectCookieManager' => $this->redirectCookieManager, 'hostChecker' => $this->hostChecker, ] ); diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml old mode 100644 new mode 100755 index a181d6dd217fd..6d07814b362c2 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -468,4 +468,7 @@ + From 5188efdbcfe31e02147d2fc6846ffd5d40e4d0ca Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 15:40:39 -0400 Subject: [PATCH 03/43] Test Fixes --- .../Customer/Model/Account/Redirect.php | 3 ++ .../Customer/Model/RedirectCookieManager.php | 5 +++ .../Test/Unit/Model/Account/RedirectTest.php | 32 ++++++++++--------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index c2e66e30b685f..f3985b5b92959 100755 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -24,6 +24,8 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) + * */ class Redirect { @@ -89,6 +91,7 @@ class Redirect private $session; /** + * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @param RequestInterface $request * @param Session $customerSession * @param ScopeConfigInterface $scopeConfig diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php index 04c87717fe215..aefdf51bd776a 100755 --- a/app/code/Magento/Customer/Model/RedirectCookieManager.php +++ b/app/code/Magento/Customer/Model/RedirectCookieManager.php @@ -11,6 +11,11 @@ use Magento\Store\Api\Data\StoreInterface; use Magento\Customer\Api\RedirectCookieManagerInterface; +/** + * Customer redirect cookie manager + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) + * + */ class RedirectCookieManager implements RedirectCookieManagerInterface { /** diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php index 66971bc15d88f..204babe62491c 100755 --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -97,21 +97,23 @@ protected function setUp() $this->customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class) ->disableOriginalConstructor() - ->setMethods([ - 'getLastCustomerId', - 'isLoggedIn', - 'getId', - 'setLastCustomerId', - 'unsBeforeAuthUrl', - 'getBeforeAuthUrl', - 'setBeforeAuthUrl', - 'getAfterAuthUrl', - 'setAfterAuthUrl', - 'getBeforeRequestParams', - 'getBeforeModuleName', - 'getBeforeControllerName', - 'getBeforeAction', - ]) + ->setMethods( + [ + 'getLastCustomerId', + 'isLoggedIn', + 'getId', + 'setLastCustomerId', + 'unsBeforeAuthUrl', + 'getBeforeAuthUrl', + 'setBeforeAuthUrl', + 'getAfterAuthUrl', + 'setAfterAuthUrl', + 'getBeforeRequestParams', + 'getBeforeModuleName', + 'getBeforeControllerName', + 'getBeforeAction', + ] + ) ->getMock(); $this->scopeConfig = $this->getMockForAbstractClass(\Magento\Framework\App\Config\ScopeConfigInterface::class); From 3cf8f224a3f850aa0838b700ba390eb25fd1f704 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 15:46:27 -0400 Subject: [PATCH 04/43] Signed CLA From 75970034babbf4525a2ccf5bf4ecfbe4d55fa897 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 16:26:10 -0400 Subject: [PATCH 05/43] Fixed Code Style Issues --- .../Api/RedirectCookieManagerInterface.php | 41 ------------------- .../Customer/Model/Account/Redirect.php | 13 +++--- .../Customer/Model/RedirectCookieManager.php | 18 +++++--- app/code/Magento/Customer/etc/di.xml | 3 -- 4 files changed, 20 insertions(+), 55 deletions(-) delete mode 100755 app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php diff --git a/app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php b/app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php deleted file mode 100755 index 5f4f1f6f917de..0000000000000 --- a/app/code/Magento/Customer/Api/RedirectCookieManagerInterface.php +++ /dev/null @@ -1,41 +0,0 @@ -request = $request; @@ -254,6 +255,7 @@ private function applyRedirect($url) * Get Cookie manager. For release backward compatibility. * * @deprecated 100.0.10 + * @see \Magento\Customer\Model\RedirectCookieManager * @return CookieManagerInterface */ protected function getCookieManager() @@ -268,6 +270,7 @@ protected function getCookieManager() * Set cookie manager. For unit tests. * * @deprecated 100.0.10 + * @see \Magento\Customer\Model\RedirectCookieManager * @param object $value * @return void */ diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php index aefdf51bd776a..61b8282ff8378 100755 --- a/app/code/Magento/Customer/Model/RedirectCookieManager.php +++ b/app/code/Magento/Customer/Model/RedirectCookieManager.php @@ -18,9 +18,6 @@ */ class RedirectCookieManager implements RedirectCookieManagerInterface { - /** - * Cookie name - */ const COOKIE_NAME = 'login_redirect'; /** @@ -46,7 +43,9 @@ public function __construct( } /** - * {@inheritdoc} + * Get redirect route from cookie for case of successful login/registration + * + * @return null|string */ public function getRedirectCookie() { @@ -54,7 +53,11 @@ public function getRedirectCookie() } /** - * {@inheritdoc} + * Save redirect route to cookie for case of successful login/registration + * + * @param string $route + * @param StoreInterface $store + * @return void */ public function setRedirectCookie($route, StoreInterface $store) { @@ -66,7 +69,10 @@ public function setRedirectCookie($route, StoreInterface $store) } /** - * {@inheritdoc} + * Clear cookie with requested route + * + * @param StoreInterface $store + * @return void */ public function clearRedirectCookie(StoreInterface $store) { diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 6d07814b362c2..a181d6dd217fd 100755 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -468,7 +468,4 @@ - From 94138920f8c54365bc29f72b63b3a2de9c04a0a0 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 16:35:28 -0400 Subject: [PATCH 06/43] Unit Tests Fix --- .../Customer/Test/Unit/Model/Account/RedirectTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php index 204babe62491c..5efef491adae1 100755 --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -8,7 +8,7 @@ namespace Magento\Customer\Test\Unit\Model\Account; -use Magento\Customer\Api\RedirectCookieManagerInterface; +use Magento\Customer\Model\RedirectCookieManager; use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; @@ -82,7 +82,7 @@ class RedirectTest extends \PHPUnit\Framework\TestCase protected $resultFactory; /** - * @var RedirectCookieManagerInterface | \PHPUnit_Framework_MockObject_MockObject + * @var RedirectCookieManager | \PHPUnit_Framework_MockObject_MockObject */ protected $redirectCookieManager; @@ -147,7 +147,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->redirectCookieManager = $this->getMockBuilder(RedirectCookieManagerInterface::class) + $this->redirectCookieManager = $this->getMockBuilder(RedirectCookieManager::class) ->disableOriginalConstructor() ->getMock(); From 9f2bbc2c0060ce884c186a627403c1296080fe2d Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 16:49:09 -0400 Subject: [PATCH 07/43] Interface removed --- app/code/Magento/Customer/Model/RedirectCookieManager.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php index 61b8282ff8378..28c85a7f1a9a1 100755 --- a/app/code/Magento/Customer/Model/RedirectCookieManager.php +++ b/app/code/Magento/Customer/Model/RedirectCookieManager.php @@ -9,14 +9,13 @@ use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; use Magento\Framework\Stdlib\CookieManagerInterface; use Magento\Store\Api\Data\StoreInterface; -use Magento\Customer\Api\RedirectCookieManagerInterface; /** * Customer redirect cookie manager * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) * */ -class RedirectCookieManager implements RedirectCookieManagerInterface +class RedirectCookieManager { const COOKIE_NAME = 'login_redirect'; From bfa636f75b220e3a59cb168ccc79b6ccdb055e07 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 17:10:32 -0400 Subject: [PATCH 08/43] Code Style --- app/code/Magento/Customer/Model/RedirectCookieManager.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php index 28c85a7f1a9a1..79ca50e14e38a 100755 --- a/app/code/Magento/Customer/Model/RedirectCookieManager.php +++ b/app/code/Magento/Customer/Model/RedirectCookieManager.php @@ -13,7 +13,6 @@ /** * Customer redirect cookie manager * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) - * */ class RedirectCookieManager { From 6446aed759f9ed44c1fecde4632e14f786b3117a Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Tue, 8 Oct 2019 17:50:06 -0400 Subject: [PATCH 09/43] Current file(s) contain protected modifier for method or property. (phpProtectedModifier) --- app/code/Magento/Customer/Model/RedirectCookieManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php index 79ca50e14e38a..27a6be6671f30 100755 --- a/app/code/Magento/Customer/Model/RedirectCookieManager.php +++ b/app/code/Magento/Customer/Model/RedirectCookieManager.php @@ -21,12 +21,12 @@ class RedirectCookieManager /** * @var CookieMetadataFactory */ - protected $cookieMetadataFactory; + private $cookieMetadataFactory; /** * @var CookieManagerInterface */ - protected $cookieManager; + private $cookieManager; /** * @param CookieMetadataFactory $cookieMetadataFactory From b3abb06344d88d366a23f32a144f3d70abe4fb3c Mon Sep 17 00:00:00 2001 From: Vaha Date: Wed, 8 Jan 2020 20:10:59 +0200 Subject: [PATCH 10/43] #26314: fixed logic for updating map price for selected swatch option on product list --- .../Magento/Msrp/view/base/web/js/msrp.js | 35 +++++++++++-------- .../view/base/web/js/swatch-renderer.js | 11 +++--- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Msrp/view/base/web/js/msrp.js b/app/code/Magento/Msrp/view/base/web/js/msrp.js index 65af87d85de51..c3d9677404f31 100644 --- a/app/code/Magento/Msrp/view/base/web/js/msrp.js +++ b/app/code/Magento/Msrp/view/base/web/js/msrp.js @@ -299,8 +299,9 @@ define([ * @param {Event} event * @param {mixed} priceIndex * @param {Object} prices + * @param {Object|undefined} $priceBox */ - onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices) { + onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices, $priceBox = undefined) { var defaultMsrp, defaultPrice, @@ -322,18 +323,20 @@ define([ finalPrice = prices[priceIndex].finalPrice.amount; if (msrpPrice === null || msrpPrice <= finalPrice) { - this.updateNonMsrpPrice(priceUtils.formatPrice(finalPrice)); + this.updateNonMsrpPrice(priceUtils.formatPrice(finalPrice), $priceBox); } else { this.updateMsrpPrice( priceUtils.formatPrice(finalPrice), priceUtils.formatPrice(msrpPrice), - false); + false, + $priceBox); } } else { this.updateMsrpPrice( priceUtils.formatPrice(defaultPrice), priceUtils.formatPrice(defaultMsrp), - true); + true, + $priceBox); } }, @@ -343,13 +346,14 @@ define([ * @param {String} finalPrice * @param {String} msrpPrice * @param {Boolean} useDefaultPrice + * @param {Object|undefined} $priceBox */ - updateMsrpPrice: function (finalPrice, msrpPrice, useDefaultPrice) { + updateMsrpPrice: function (finalPrice, msrpPrice, useDefaultPrice, $priceBox) { var options = this.tierOptions || this.options; - $(this.options.fallbackPriceContainer).hide(); - $(this.options.displayPriceContainer).show(); - $(this.options.mapInfoLinks).show(); + $(this.options.fallbackPriceContainer, $priceBox).hide(); + $(this.options.displayPriceContainer, $priceBox).show(); + $(this.options.mapInfoLinks, $priceBox).show(); if (useDefaultPrice || !this.wasOpened) { if (this.$popup) { @@ -357,14 +361,14 @@ define([ this.$popup.find(this.options.priceLabelId).html(options.realPrice); } - $(this.options.displayPriceElement).html(msrpPrice); + $(this.options.displayPriceElement, $priceBox).html(msrpPrice); this.wasOpened = true; } if (!useDefaultPrice) { this.$popup.find(this.options.msrpPriceElement).html(msrpPrice); this.$popup.find(this.options.priceElement).html(finalPrice); - $(this.options.displayPriceElement).html(msrpPrice); + $(this.options.displayPriceElement, $priceBox).html(msrpPrice); } }, @@ -372,12 +376,13 @@ define([ * Display non MAP price for irrelevant products * * @param {String} price + * @param {Object|undefined} $priceBox */ - updateNonMsrpPrice: function (price) { - $(this.options.fallbackPriceElement).html(price); - $(this.options.displayPriceContainer).hide(); - $(this.options.mapInfoLinks).hide(); - $(this.options.fallbackPriceContainer).show(); + updateNonMsrpPrice: function (price, $priceBox) { + $(this.options.fallbackPriceElement, $priceBox).html(price); + $(this.options.displayPriceContainer, $priceBox).hide(); + $(this.options.mapInfoLinks, $priceBox).hide(); + $(this.options.fallbackPriceContainer, $priceBox).show(); }, /** diff --git a/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js index ee55beb440f59..67504563fa933 100644 --- a/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js @@ -723,7 +723,9 @@ define([ $label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass), attributeId = $parent.attr('attribute-id'), $input = $parent.find('.' + $widget.options.classes.attributeInput), - checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']); + checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']), + $priceBox = $widget.element.parents($widget.options.selectorProduct) + .find(this.options.selectorProductPrice); if ($widget.inProductList) { $input = $widget.productForm.find( @@ -751,16 +753,15 @@ define([ $widget._Rebuild(); - if ($widget.element.parents($widget.options.selectorProduct) - .find(this.options.selectorProductPrice).is(':data(mage-priceBox)') - ) { + if ($priceBox.is(':data(mage-priceBox)')) { $widget._UpdatePrice(); } $(document).trigger('updateMsrpPriceBlock', [ _.findKey($widget.options.jsonConfig.index, $widget.options.jsonConfig.defaultValues), - $widget.options.jsonConfig.optionPrices + $widget.options.jsonConfig.optionPrices, + $priceBox ]); if (parseInt(checkAdditionalData['update_product_preview_image'], 10) === 1) { From df37523bd44a63fe3c220677bf7a5d6ed310b268 Mon Sep 17 00:00:00 2001 From: Vaha Date: Wed, 22 Jan 2020 16:25:08 +0200 Subject: [PATCH 11/43] #26314: removed default value for parameter --- app/code/Magento/Msrp/view/base/web/js/msrp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Msrp/view/base/web/js/msrp.js b/app/code/Magento/Msrp/view/base/web/js/msrp.js index c3d9677404f31..db407fbb22ce0 100644 --- a/app/code/Magento/Msrp/view/base/web/js/msrp.js +++ b/app/code/Magento/Msrp/view/base/web/js/msrp.js @@ -301,7 +301,7 @@ define([ * @param {Object} prices * @param {Object|undefined} $priceBox */ - onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices, $priceBox = undefined) { + onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices, $priceBox) { var defaultMsrp, defaultPrice, From 1f96b873283229aa6892444244475d9992c0d8f2 Mon Sep 17 00:00:00 2001 From: Dasharath Date: Sun, 2 Feb 2020 15:00:42 +0530 Subject: [PATCH 12/43] [26054-Do not duplicate SEO meta data when duplicating a product] --- app/code/Magento/Catalog/Model/Product/Copier.php | 7 +++---- .../Magento/Catalog/Test/Unit/Model/Product/CopierTest.php | 3 +++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Copier.php b/app/code/Magento/Catalog/Model/Product/Copier.php index a7f7bad1a5167..22419123d1614 100644 --- a/app/code/Magento/Catalog/Model/Product/Copier.php +++ b/app/code/Magento/Catalog/Model/Product/Copier.php @@ -78,6 +78,9 @@ public function copy(Product $product) $productData = $this->removeStockItem($productData); $duplicate->setData($productData); $duplicate->setOptions([]); + $duplicate->setMetaTitle(null); + $duplicate->setMetaKeyword(null); + $duplicate->setMetaDescription(null); $duplicate->setIsDuplicate(true); $duplicate->setOriginalLinkId($product->getData($metadata->getLinkField())); $duplicate->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); @@ -89,10 +92,6 @@ public function copy(Product $product) $this->setDefaultUrl($product, $duplicate); $this->setStoresUrl($product, $duplicate); $this->getOptionRepository()->duplicate($product, $duplicate); - $product->getResource()->duplicate( - $product->getData($metadata->getLinkField()), - $duplicate->getData($metadata->getLinkField()) - ); return $duplicate; } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php index 809fa0225278c..34fddc06f1c42 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php @@ -197,6 +197,9 @@ public function testCopy() $duplicateMock->expects($this->once())->method('setCreatedAt')->with(null); $duplicateMock->expects($this->once())->method('setUpdatedAt')->with(null); $duplicateMock->expects($this->once())->method('setId')->with(null); + $duplicateMock->expects($this->once())->method('setMetaTitle')->with(null); + $duplicateMock->expects($this->once())->method('setMetaKeyword')->with(null); + $duplicateMock->expects($this->once())->method('setMetaDescription')->with(null); $duplicateMock->expects($this->atLeastOnce())->method('getStoreIds')->willReturn([]); $duplicateMock->expects($this->atLeastOnce())->method('setData')->willReturn($duplicateMock); $this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock); From 16da7068cdcc6077ff9ea2f58a0b20f56932e310 Mon Sep 17 00:00:00 2001 From: Alexander Lukyanov Date: Mon, 3 Feb 2020 12:57:45 -0500 Subject: [PATCH 13/43] Update Redirect.php --- app/code/Magento/Customer/Model/Account/Redirect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index e0e5730c4281b..4e3907e71eff2 100755 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -29,7 +29,7 @@ */ class Redirect { - /** @deprecated + /** @deprecated moved into its own class * @see \Magento\Customer\Model\RedirectCookieManager * URL to redirect user on successful login or registration */ From bde58b9ba5cd54cd82d80df1b82b48003eb3d010 Mon Sep 17 00:00:00 2001 From: Vova Yatsyuk Date: Tue, 4 Feb 2020 10:01:51 +0200 Subject: [PATCH 14/43] Use '===' operator to check if file was written. This prevents incorrect logic when writing empty string (0 bytes). --- lib/internal/Magento/Framework/Filesystem/Driver/File.php | 2 +- lib/internal/Magento/Framework/Filesystem/Driver/Http.php | 2 +- lib/internal/Magento/Framework/Filesystem/Io/File.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index 59c9775d73a0a..3251f5af1bad3 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -552,7 +552,7 @@ public function touch($path, $modificationTime = null) public function filePutContents($path, $content, $mode = null) { $result = @file_put_contents($this->getScheme() . $path, $content, $mode); - if (!$result) { + if ($result === false) { throw new FileSystemException( new \Magento\Framework\Phrase( 'The specified "%1" file couldn\'t be written. %2', diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php index f32624f4e7513..9f76bb33335d3 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php @@ -109,7 +109,7 @@ public function fileGetContents($path, $flags = null, $context = null) public function filePutContents($path, $content, $mode = null, $context = null) { $result = @file_put_contents($this->getScheme() . $path, $content, $mode, $context); - if (!$result) { + if ($result === false) { throw new FileSystemException( new \Magento\Framework\Phrase( 'The specified "%1" file couldn\'t be written. %2', diff --git a/lib/internal/Magento/Framework/Filesystem/Io/File.php b/lib/internal/Magento/Framework/Filesystem/Io/File.php index 8fec7f7630257..97b121beb42c2 100644 --- a/lib/internal/Magento/Framework/Filesystem/Io/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Io/File.php @@ -479,7 +479,7 @@ public function write($filename, $src, $mode = null) } else { $result = @file_put_contents($filename, $src); } - if ($mode !== null && $result) { + if ($mode !== null && $result !== false) { @chmod($filename, $mode); } $this->_iwd(); From 2449839962b1ee6a5e6f24e75c358b05942e9892 Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal Date: Wed, 5 Feb 2020 13:13:58 +0200 Subject: [PATCH 15/43] Unit test for \Magento\Captcha\Observer\CheckUserForgotPasswordBackendObserver --- ...kUserForgotPasswordBackendObserverTest.php | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php new file mode 100644 index 0000000000000..346814aca2084 --- /dev/null +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php @@ -0,0 +1,188 @@ +helperMock = $this->createMock(DataHelper::class); + $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class); + $this->sessionMock = $this->getMockBuilder(SessionManagerInterface::class) + ->setMethods(['setEmail']) + ->getMockForAbstractClass(); + $this->actionFlagMock = $this->createMock(ActionFlag::class); + $this->messageManagerMock = $this->createMock(ManagerInterface::class); + + $objectManager = new ObjectManagerHelper($this); + $this->observer = $objectManager->getObject( + CheckUserForgotPasswordBackendObserver::class, + [ + '_helper' => $this->helperMock, + 'captchaStringResolver' => $this->captchaStringResolverMock, + '_session' => $this->sessionMock, + '_actionFlag' => $this->actionFlagMock, + 'messageManager' => $this->messageManagerMock + ] + ); + + $this->captchaMock = $this->getMockBuilder(CaptchaInterface::class) + ->setMethods(['isRequired', 'isCorrect']) + ->getMockForAbstractClass(); + $this->helperMock->expects($this->once()) + ->method('getCaptcha') + ->with($formId) + ->willReturn($this->captchaMock); + + $requestMock = $this->createMock(HttpRequest::class); + $requestMock->expects($this->any()) + ->method('getParam') + ->with('email') + ->willReturn($email); + $requestMock->expects($this->any()) + ->method('getParams') + ->willReturn($requestParams); + $this->httpResponseMock = $this->createMock(HttpResponse::class); + + $this->controllerMock = $this->getMockBuilder(Action::class) + ->disableOriginalConstructor() + ->setMethods(['getUrl', 'getRequest', 'getResponse']) + ->getMockForAbstractClass(); + $this->controllerMock->expects($this->any()) + ->method('getRequest') + ->willReturn($requestMock); + $this->controllerMock->expects($this->any()) + ->method('getResponse') + ->willReturn($this->httpResponseMock); + + $this->eventObserverMock = $this->createPartialMock(Observer::class, ['getControllerAction']); + $this->eventObserverMock->expects($this->any()) + ->method('getControllerAction') + ->willReturn($this->controllerMock); + } + + /** + * Test case when Captcha is required and was entered correctly. + */ + public function testExecuteWhenCaptchaIsCorrect() + { + $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(true); + $this->captchaMock->expects($this->once())->method('isCorrect')->willReturn(true); + $this->messageManagerMock->expects($this->never())->method('addErrorMessage'); + $this->httpResponseMock->expects($this->never())->method('setRedirect'); + + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when Captcha is required and was entered incorrectly. + */ + public function testExecuteWhenCaptchaIsIncorrect() + { + $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(true); + $this->captchaMock->expects($this->once())->method('isCorrect')->willReturn(false); + + $this->sessionMock->expects($this->once())->method('setEmail'); + $this->actionFlagMock->expects($this->once())->method('set'); + $this->controllerMock->expects($this->once())->method('getUrl'); + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with(__('Incorrect CAPTCHA')); + $this->httpResponseMock->expects($this->once())->method('setRedirect')->willReturnSelf(); + + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when Captcha is not required. + */ + public function testExecuteWhenCaptchaIsNotRequired() + { + $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(false); + $this->messageManagerMock->expects($this->never())->method('addErrorMessage'); + $this->httpResponseMock->expects($this->never())->method('setRedirect'); + + $this->observer->execute($this->eventObserverMock); + } +} From 17990cb1670acc72e92d568aae43c48f5b5e23ee Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal Date: Wed, 5 Feb 2020 14:32:24 +0200 Subject: [PATCH 16/43] Add annotation --- .../Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php index 346814aca2084..892494b4db8df 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php @@ -25,6 +25,7 @@ /** * Unit Test for \Magento\Captcha\Observer\CheckUserForgotPasswordBackendObserver + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CheckUserForgotPasswordBackendObserverTest extends TestCase { From 0d17e0af1904c1a8a7ac6aadd6280faa527ef1f8 Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal Date: Wed, 5 Feb 2020 16:19:39 +0200 Subject: [PATCH 17/43] Add a new test case, refactoring --- ...kUserForgotPasswordBackendObserverTest.php | 71 +++++++++++++++---- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php index 892494b4db8df..584e7eb2e215f 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php @@ -29,6 +29,9 @@ */ class CheckUserForgotPasswordBackendObserverTest extends TestCase { + const STUB_EMAIL = 'stub@test.mail'; + const STUB_REQUEST_PARAMS = ['STUB_PARAM']; + /** * @var MockObject|DataHelper */ @@ -60,7 +63,7 @@ class CheckUserForgotPasswordBackendObserverTest extends TestCase private $observer; /** - * @var MockObject + * @var MockObject|CaptchaInterface */ private $captchaMock; @@ -79,14 +82,17 @@ class CheckUserForgotPasswordBackendObserverTest extends TestCase */ private $httpResponseMock; + /** + * @var MockObject|HttpRequest + */ + private $requestMock; + /** * @inheritDoc */ protected function setUp() { $formId = 'backend_forgotpassword'; - $email = 'stub@test.mail'; - $requestParams = ['STUB_PARAM']; $this->helperMock = $this->createMock(DataHelper::class); $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class); @@ -116,14 +122,7 @@ protected function setUp() ->with($formId) ->willReturn($this->captchaMock); - $requestMock = $this->createMock(HttpRequest::class); - $requestMock->expects($this->any()) - ->method('getParam') - ->with('email') - ->willReturn($email); - $requestMock->expects($this->any()) - ->method('getParams') - ->willReturn($requestParams); + $this->requestMock = $this->createMock(HttpRequest::class); $this->httpResponseMock = $this->createMock(HttpResponse::class); $this->controllerMock = $this->getMockBuilder(Action::class) @@ -132,7 +131,7 @@ protected function setUp() ->getMockForAbstractClass(); $this->controllerMock->expects($this->any()) ->method('getRequest') - ->willReturn($requestMock); + ->willReturn($this->requestMock); $this->controllerMock->expects($this->any()) ->method('getResponse') ->willReturn($this->httpResponseMock); @@ -148,12 +147,11 @@ protected function setUp() */ public function testExecuteWhenCaptchaIsCorrect() { + $this->configureRequestMockWithStubValues(); $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(true); $this->captchaMock->expects($this->once())->method('isCorrect')->willReturn(true); - $this->messageManagerMock->expects($this->never())->method('addErrorMessage'); - $this->httpResponseMock->expects($this->never())->method('setRedirect'); - $this->observer->execute($this->eventObserverMock); + $this->executeOriginalMethodExpectsNoError(); } /** @@ -161,6 +159,7 @@ public function testExecuteWhenCaptchaIsCorrect() */ public function testExecuteWhenCaptchaIsIncorrect() { + $this->configureRequestMockWithStubValues(); $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(true); $this->captchaMock->expects($this->once())->method('isCorrect')->willReturn(false); @@ -180,7 +179,49 @@ public function testExecuteWhenCaptchaIsIncorrect() */ public function testExecuteWhenCaptchaIsNotRequired() { + $this->configureRequestMockWithStubValues(); $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(false); + + $this->executeOriginalMethodExpectsNoError(); + } + + /** + * Test case when email is not provided + */ + public function testExecuteWhenEmailParamIsNotPresent() + { + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('email') + ->willReturn(null); + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn(self::STUB_REQUEST_PARAMS); + $this->captchaMock->expects($this->never())->method('isRequired'); + $this->captchaMock->expects($this->never())->method('isCorrect'); + + $this->executeOriginalMethodExpectsNoError(); + } + + /** + * Stub params for Request Mock + */ + private function configureRequestMockWithStubValues() + { + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('email') + ->willReturn(self::STUB_EMAIL); + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn(self::STUB_REQUEST_PARAMS); + } + + /** + * Run original method, expect there is no error + */ + private function executeOriginalMethodExpectsNoError() + { $this->messageManagerMock->expects($this->never())->method('addErrorMessage'); $this->httpResponseMock->expects($this->never())->method('setRedirect'); From 89b0a9d4edd2380672ee813d812fe8fbf715eb61 Mon Sep 17 00:00:00 2001 From: Nazar Klovanych Date: Thu, 6 Feb 2020 11:04:29 +0200 Subject: [PATCH 18/43] refactoring, fix unit test --- .../Test/Unit/Model/Product/CopierTest.php | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php index 34fddc06f1c42..a1cbc59e56300 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php @@ -5,10 +5,18 @@ */ namespace Magento\Catalog\Test\Unit\Model\Product; +use Magento\Catalog\Api\Data\ProductExtension; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\Product\Copier; +use Magento\Catalog\Model\Product\CopyConstructorInterface; +use Magento\Catalog\Model\Product\Option\Repository; +use Magento\Catalog\Model\ProductFactory; +use Magento\CatalogInventory\Api\Data\StockItemInterface; +use Magento\Framework\EntityManager\EntityMetadata; +use Magento\Framework\EntityManager\MetadataPool; +use PHPUnit\Framework\MockObject\MockObject; /** * Test for Magento\Catalog\Model\Product\Copier class. @@ -18,62 +26,60 @@ class CopierTest extends \PHPUnit\Framework\TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $optionRepositoryMock; + private $optionRepositoryMock; /** * @var Copier */ - protected $_model; + private $_model; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $copyConstructorMock; + private $copyConstructorMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $productFactoryMock; + private $productFactoryMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $productMock; + private $productMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - protected $metadata; + private $metadata; /** - * @var ScopeOverriddenValue|\PHPUnit_Framework_MockObject_MockObject + * @var ScopeOverriddenValue|MockObject */ private $scopeOverriddenValue; + /** + * @ingeritdoc + */ protected function setUp() { - $this->copyConstructorMock = $this->createMock(\Magento\Catalog\Model\Product\CopyConstructorInterface::class); - $this->productFactoryMock = $this->createPartialMock( - \Magento\Catalog\Model\ProductFactory::class, - ['create'] - ); - $this->optionRepositoryMock = $this->createMock( - \Magento\Catalog\Model\Product\Option\Repository::class - ); - $this->optionRepositoryMock; + $this->metadata = $this->createMock(EntityMetadata::class); + $metadataPool = $this->createMock(MetadataPool::class); + + $this->copyConstructorMock = $this->createMock(CopyConstructorInterface::class); + $this->productFactoryMock = $this->createPartialMock(ProductFactory::class, ['create']); + $this->optionRepositoryMock = $this->createMock(Repository::class); $this->productMock = $this->createMock(Product::class); - $this->productMock->expects($this->any())->method('getEntityId')->willReturn(1); $this->scopeOverriddenValue = $this->createMock(ScopeOverriddenValue::class); - $this->metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadata::class) - ->disableOriginalConstructor() - ->getMock(); - $metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) - ->disableOriginalConstructor() - ->getMock(); - $metadataPool->expects($this->any())->method('getMetadata')->willReturn($this->metadata); + $this->productMock->expects($this->any()) + ->method('getEntityId') + ->willReturn(1); + $metadataPool->expects($this->any()) + ->method('getMetadata') + ->willReturn($this->metadata); $this->_model = new Copier( $this->copyConstructorMock, @@ -95,9 +101,8 @@ protected function setUp() */ public function testCopy() { - $stockItem = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockItemInterface::class) - ->getMock(); - $extensionAttributes = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductExtension::class) + $stockItem = $this->createMock(StockItemInterface::class); + $extensionAttributes = $this->getMockBuilder(ProductExtension::class) ->setMethods(['getStockItem', 'setData']) ->getMock(); $extensionAttributes @@ -179,6 +184,9 @@ public function testCopy() 'setUrlKey', 'setStoreId', 'getStoreIds', + 'setMetaTitle', + 'setMetaKeyword', + 'setMetaDescription' ] ); $this->productFactoryMock->expects($this->once())->method('create')->will($this->returnValue($duplicateMock)); @@ -216,7 +224,6 @@ public function testCopy() $this->optionRepositoryMock->expects($this->once()) ->method('duplicate') ->with($this->productMock, $duplicateMock); - $resourceMock->expects($this->once())->method('duplicate')->with(1, 2); $this->assertEquals($duplicateMock, $this->_model->copy($this->productMock)); } From bfeadd7e3971a278784155cfddefc80c7aeeb07d Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Thu, 6 Feb 2020 17:15:32 -0500 Subject: [PATCH 19/43] Removed Magento/Customer/Model/RedirectCookieManager. Deprecated getCookieManager, setCookieManager, getRedirectCookie, setRedirectCookie, clearRedirectCookie --- .../Customer/Model/Account/Redirect.php | 47 ++++++----- .../Customer/Model/RedirectCookieManager.php | 81 ------------------- .../Test/Unit/Model/Account/RedirectTest.php | 10 +-- 3 files changed, 30 insertions(+), 108 deletions(-) delete mode 100755 app/code/Magento/Customer/Model/RedirectCookieManager.php diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index e0e5730c4281b..583f25dbf95c9 100755 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -20,7 +20,6 @@ use Magento\Framework\Url\DecoderInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\Stdlib\CookieManagerInterface; -use Magento\Customer\Model\RedirectCookieManager; /** * Account Redirect @@ -29,10 +28,7 @@ */ class Redirect { - /** @deprecated - * @see \Magento\Customer\Model\RedirectCookieManager - * URL to redirect user on successful login or registration - */ + /** URL to redirect user on successful login or registration */ const LOGIN_REDIRECT_URL = 'login_redirect'; /** @@ -72,14 +68,9 @@ class Redirect protected $resultFactory; /** - * @var CookieManagerInterface - */ - protected $cookieManager; - - /** - * @var RedirectCookieManager + * @var CookieMetadataFactory */ - protected $redirectCookieManager; + protected $cookieMetadataFactory; /** * @var HostChecker @@ -101,7 +92,7 @@ class Redirect * @param DecoderInterface $urlDecoder * @param CustomerUrl $customerUrl * @param ResultFactory $resultFactory - * @param RedirectCookieManager $redirectCookieManager + * @param CookieMetadataFactory $cookieMetadataFactory * @param HostChecker|null $hostChecker */ public function __construct( @@ -113,7 +104,7 @@ public function __construct( DecoderInterface $urlDecoder, CustomerUrl $customerUrl, ResultFactory $resultFactory, - RedirectCookieManager $redirectCookieManager, + CookieMetadataFactory $cookieMetadataFactory HostChecker $hostChecker = null ) { $this->request = $request; @@ -123,8 +114,8 @@ public function __construct( $this->url = $url; $this->urlDecoder = $urlDecoder; $this->customerUrl = $customerUrl; + $this->cookieMetadataFactory = $cookieMetadataFactory; $this->resultFactory = $resultFactory; - $this->redirectCookieManager = $redirectCookieManager; $this->hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); } @@ -254,8 +245,8 @@ private function applyRedirect($url) /** * Get Cookie manager. For release backward compatibility. * - * @deprecated 100.0.10 - * @see \Magento\Customer\Model\RedirectCookieManager + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @return CookieManagerInterface */ protected function getCookieManager() @@ -269,8 +260,8 @@ protected function getCookieManager() /** * Set cookie manager. For unit tests. * - * @deprecated 100.0.10 - * @see \Magento\Customer\Model\RedirectCookieManager + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @param object $value * @return void */ @@ -282,31 +273,43 @@ public function setCookieManager($value) /** * Get redirect route from cookie for case of successful login/registration * + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @return null|string */ public function getRedirectCookie() { - return $this->redirectCookieManager->getRedirectCookie(); + return $this->getCookieManager()->getCookie(self::LOGIN_REDIRECT_URL, null); } /** * Save redirect route to cookie for case of successful login/registration * + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @param string $route * @return void */ public function setRedirectCookie($route) { - $this->redirectCookieManager->setRedirectCookie($route, $this->storeManager->getStore()); + $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setHttpOnly(true) + ->setDuration(3600) + ->setPath($this->storeManager->getStore()->getStorePath()); + $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route, $cookieMetadata); } /** * Clear cookie with requested route * + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @return void */ public function clearRedirectCookie() { - $this->redirectCookieManager->clearRedirectCookie($this->storeManager->getStore()); + $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setPath($this->storeManager->getStore()->getStorePath()); + $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL, $cookieMetadata); } } diff --git a/app/code/Magento/Customer/Model/RedirectCookieManager.php b/app/code/Magento/Customer/Model/RedirectCookieManager.php deleted file mode 100755 index 27a6be6671f30..0000000000000 --- a/app/code/Magento/Customer/Model/RedirectCookieManager.php +++ /dev/null @@ -1,81 +0,0 @@ -cookieMetadataFactory = $cookieMetadataFactory; - $this->cookieManager = $cookieManager; - } - - /** - * Get redirect route from cookie for case of successful login/registration - * - * @return null|string - */ - public function getRedirectCookie() - { - return $this->cookieManager->getCookie(self::COOKIE_NAME, null); - } - - /** - * Save redirect route to cookie for case of successful login/registration - * - * @param string $route - * @param StoreInterface $store - * @return void - */ - public function setRedirectCookie($route, StoreInterface $store) - { - $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() - ->setHttpOnly(true) - ->setDuration(3600) - ->setPath($store->getStorePath()); - $this->cookieManager->setPublicCookie(self::COOKIE_NAME, $route, $cookieMetadata); - } - - /** - * Clear cookie with requested route - * - * @param StoreInterface $store - * @return void - */ - public function clearRedirectCookie(StoreInterface $store) - { - $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() - ->setPath($store->getStorePath()); - $this->cookieManager->deleteCookie(self::COOKIE_NAME, $cookieMetadata); - } -} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php index 5efef491adae1..f520182e51199 100755 --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -8,7 +8,7 @@ namespace Magento\Customer\Test\Unit\Model\Account; -use Magento\Customer\Model\RedirectCookieManager; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; @@ -82,9 +82,9 @@ class RedirectTest extends \PHPUnit\Framework\TestCase protected $resultFactory; /** - * @var RedirectCookieManager | \PHPUnit_Framework_MockObject_MockObject + * @var CookieMetadataFactory | \PHPUnit_Framework_MockObject_MockObject */ - protected $redirectCookieManager; + protected $cookieMetadataFactory; /** * @var HostChecker | \PHPUnit_Framework_MockObject_MockObject @@ -147,7 +147,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->redirectCookieManager = $this->getMockBuilder(RedirectCookieManager::class) + $this->cookieMetadataFactory = $this->getMockBuilder(CookieMetadataFactory::class) ->disableOriginalConstructor() ->getMock(); @@ -167,7 +167,7 @@ protected function setUp() 'urlDecoder' => $this->urlDecoder, 'customerUrl' => $this->customerUrl, 'resultFactory' => $this->resultFactory, - 'redirectCookieManager' => $this->redirectCookieManager, + 'cookieMetadataFactory' => $this->cookieMetadataFactory, 'hostChecker' => $this->hostChecker, ] ); From dc416a9bb545517384bff75c1bc1e181a1343af0 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Thu, 6 Feb 2020 17:38:03 -0500 Subject: [PATCH 20/43] Removed Magento/Customer/Model/RedirectCookieManager. Deprecated getCookieManager, setCookieManager, getRedirectCookie, setRedirectCookie, clearRedirectCookie --- app/code/Magento/Customer/Model/Account/Redirect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index ebc2091410489..0d2cbdf6a6051 100755 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -105,7 +105,7 @@ public function __construct( DecoderInterface $urlDecoder, CustomerUrl $customerUrl, ResultFactory $resultFactory, - CookieMetadataFactory $cookieMetadataFactory + CookieMetadataFactory $cookieMetadataFactory, HostChecker $hostChecker = null ) { $this->request = $request; From 41ce59e5f53564e9e665660ccee618a390ca1de3 Mon Sep 17 00:00:00 2001 From: Alex Lukyanau Date: Thu, 6 Feb 2020 18:21:09 -0500 Subject: [PATCH 21/43] Removed Magento/Customer/Model/RedirectCookieManager. Deprecated getCookieManager, setCookieManager, getRedirectCookie, setRedirectCookie, clearRedirectCookie --- app/code/Magento/Customer/Model/Account/Redirect.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index 0d2cbdf6a6051..ba1f72369f606 100755 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -73,6 +73,11 @@ class Redirect */ protected $cookieMetadataFactory; + /** + * @var CookieManagerInterface + */ + private $cookieManager; + /** * @var HostChecker */ From 8e0d7ba31112e129a789750ad90ec574ab02c355 Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal Date: Fri, 7 Feb 2020 12:24:08 +0200 Subject: [PATCH 22/43] Fix return type in ResetAttemptForFrontendObserver and ResetAttemptForBackendObserver classes. code cleaning --- .../ResetAttemptForBackendObserver.php | 20 +++++++++++----- .../ResetAttemptForFrontendObserver.php | 23 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php b/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php index 376bffbd9a6a5..165aef3d7f587 100644 --- a/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php +++ b/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php @@ -5,20 +5,27 @@ */ namespace Magento\Captcha\Observer; +use Magento\Captcha\Model\ResourceModel\Log; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Exception\LocalizedException; +/** + * Reset captcha attempts for Backend + */ class ResetAttemptForBackendObserver implements ObserverInterface { /** - * @var \Magento\Captcha\Model\ResourceModel\LogFactory + * @var LogFactory */ public $resLogFactory; /** - * @param \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + * @param LogFactory $resLogFactory */ public function __construct( - \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + LogFactory $resLogFactory ) { $this->resLogFactory = $resLogFactory; } @@ -26,10 +33,11 @@ public function __construct( /** * Reset Attempts For Backend * - * @param \Magento\Framework\Event\Observer $observer - * @return \Magento\Captcha\Observer\ResetAttemptForBackendObserver + * @param Observer $observer + * @return Log + * @throws LocalizedException */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { return $this->resLogFactory->create()->deleteUserAttempts($observer->getUser()->getUsername()); } diff --git a/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php b/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php index dedb57ad52581..e65793cd3508e 100644 --- a/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php +++ b/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php @@ -5,20 +5,28 @@ */ namespace Magento\Captcha\Observer; +use Magento\Captcha\Model\ResourceModel\Log; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Customer\Model\Customer; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Exception\LocalizedException; +/** + * Reset captcha attempts for Frontend + */ class ResetAttemptForFrontendObserver implements ObserverInterface { /** - * @var \Magento\Captcha\Model\ResourceModel\LogFactory + * @var LogFactory */ public $resLogFactory; /** - * @param \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + * @param LogFactory $resLogFactory */ public function __construct( - \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + LogFactory $resLogFactory ) { $this->resLogFactory = $resLogFactory; } @@ -26,12 +34,13 @@ public function __construct( /** * Reset Attempts For Frontend * - * @param \Magento\Framework\Event\Observer $observer - * @return \Magento\Captcha\Observer\ResetAttemptForFrontendObserver + * @param Observer $observer + * @return Log + * @throws LocalizedException */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { - /** @var \Magento\Customer\Model\Customer $model */ + /** @var Customer $model */ $model = $observer->getModel(); return $this->resLogFactory->create()->deleteUserAttempts($model->getEmail()); From 3e0ffb71b3dbb57dcda10ceac73abd87e5834555 Mon Sep 17 00:00:00 2001 From: Ajith Date: Sat, 8 Feb 2020 11:42:25 +0530 Subject: [PATCH 23/43] No marginal space validation added --- .../Cms/view/adminhtml/ui_component/cms_block_listing.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml index 793fc7d26cb4a..af54df24b64f5 100644 --- a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml +++ b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml @@ -146,6 +146,7 @@ true + true text From e0015b4a7efbaba8b370b30ecc9e70357801183b Mon Sep 17 00:00:00 2001 From: Ajith Date: Sat, 8 Feb 2020 12:02:27 +0530 Subject: [PATCH 24/43] Covered validation with MFTF test --- .../AdminFillCmsBlockFormActionGroup.xml | 25 ++++++++++++++++ .../Mftf/Test/AdminCreateCmsBlockTest.xml | 30 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml new file mode 100644 index 0000000000000..685385382027b --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml @@ -0,0 +1,25 @@ + + + + + + + Fills in the Block Title, Identifier with marginal space, Store View and Content. PLEASE NOTE: The values are passed through arguments in test. + + + + + + + + + + + + diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml index ef4a7575c35d3..a2dafc5e3537d 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml @@ -49,4 +49,34 @@ + + + + + + <description value="Admin can not able create a CMS block with marginal space in identifier field"/> + <severity value="CRITICAL"/> + <group value="Cms"/> + </annotations> + <before> + <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> + <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> + </before> + <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnBlocksCreationForm"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <!--Verify Save&Duplicate button and Save&Close button--> + <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn1" /> + <see selector="{{BlockNewPagePageActionsSection.saveAndDuplicate}}" userInput="Save & Duplicate" stepKey="seeSaveAndDuplicate"/> + <see selector="{{BlockNewPagePageActionsSection.saveAndClose}}" userInput="Save & Close" stepKey="seeSaveAndClose"/> + <!--Create new CMS Block page with marginal space in identifier field--> + <actionGroup ref="AdminFillCmsBlockFormActionGroup" stepKey="FillOutBlockContent"> + <argument name="cmsBlockDataTitle" value="Default Block" /> + <argument name="cmsBlockDataIdentifier" value=" block " /> + <argument name="cmsBlockDataContent" value="Here is a block test. Yeah!" /> + </actionGroup> + <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn2" /> + <click selector="{{BlockNewPagePageActionsSection.saveAndClose}}" stepKey="clicksaveAndClose" /> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <see userInput="No marginal white space please" stepKey="seeNoMarginalSpaceMsgOnIdentifierField"/> + </test> </tests> From 353beeeea769ff96e780979d53a8489ea4099b4e Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Sun, 9 Feb 2020 00:04:47 +0530 Subject: [PATCH 25/43] Test is moved to seperate file --- .../Mftf/Test/AdminCreateCmsBlockTest.xml | 30 -------------- ...minCreateCmsBlockWithMarginalSpaceTest.xml | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 30 deletions(-) create mode 100644 app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml index d357eaf50d29e..6867560551915 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml @@ -42,34 +42,4 @@ <actionGroup ref="SaveAndCloseCMSBlockWithSplitButtonActionGroup" stepKey="saveAndCloseAction" /> <seeElement selector="div[data-role='grid-wrapper']" stepKey="seeGridPage" /> </test> - <test name="AdminCreateCmsBlockWithMarginalSpaceTest"> - <annotations> - <features value="Cms"/> - <stories value="CMS Block Identifier with marginal space"/> - <title value="Admin can not able create a CMS block with marginal space in identifier field"/> - <description value="Admin can not able create a CMS block with marginal space in identifier field"/> - <severity value="CRITICAL"/> - <group value="Cms"/> - </annotations> - <before> - <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> - <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> - </before> - <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnBlocksCreationForm"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <!--Verify Save&Duplicate button and Save&Close button--> - <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn1" /> - <see selector="{{BlockNewPagePageActionsSection.saveAndDuplicate}}" userInput="Save & Duplicate" stepKey="seeSaveAndDuplicate"/> - <see selector="{{BlockNewPagePageActionsSection.saveAndClose}}" userInput="Save & Close" stepKey="seeSaveAndClose"/> - <!--Create new CMS Block page with marginal space in identifier field--> - <actionGroup ref="AdminFillCmsBlockFormActionGroup" stepKey="FillOutBlockContent"> - <argument name="cmsBlockDataTitle" value="Default Block" /> - <argument name="cmsBlockDataIdentifier" value=" block " /> - <argument name="cmsBlockDataContent" value="Here is a block test. Yeah!" /> - </actionGroup> - <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn2" /> - <click selector="{{BlockNewPagePageActionsSection.saveAndClose}}" stepKey="clicksaveAndClose" /> - <waitForPageLoad stepKey="waitForPageLoad3"/> - <see userInput="No marginal white space please" stepKey="seeNoMarginalSpaceMsgOnIdentifierField"/> - </test> </tests> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml new file mode 100644 index 0000000000000..0399d0eb3ab28 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateCmsBlockWithMarginalSpaceTest"> + <annotations> + <features value="Cms"/> + <stories value="CMS Block Identifier with marginal space"/> + <title value="Admin can not able create a CMS block with marginal space in identifier field"/> + <description value="Admin can not able create a CMS block with marginal space in identifier field"/> + <severity value="CRITICAL"/> + <group value="Cms"/> + </annotations> + <before> + <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> + <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> + </before> + <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnBlocksCreationForm"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <!--Verify Save&Duplicate button and Save&Close button--> + <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn1" /> + <see selector="{{BlockNewPagePageActionsSection.saveAndDuplicate}}" userInput="Save & Duplicate" stepKey="seeSaveAndDuplicate"/> + <see selector="{{BlockNewPagePageActionsSection.saveAndClose}}" userInput="Save & Close" stepKey="seeSaveAndClose"/> + <!--Create new CMS Block page with marginal space in identifier field--> + <actionGroup ref="AdminFillCmsBlockFormActionGroup" stepKey="FillOutBlockContent"> + <argument name="cmsBlockDataTitle" value="Default Block" /> + <argument name="cmsBlockDataIdentifier" value=" block " /> + <argument name="cmsBlockDataContent" value="Here is a block test. Yeah!" /> + </actionGroup> + <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn2" /> + <click selector="{{BlockNewPagePageActionsSection.saveAndClose}}" stepKey="clicksaveAndClose" /> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <see userInput="No marginal white space please" stepKey="seeNoMarginalSpaceMsgOnIdentifierField"/> + </test> +</tests> From e500c3d89a52edf69df1753db1524a0dd560ce16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Szubert?= <bartlomiejszubert@gmail.com> Date: Wed, 15 Jan 2020 12:19:14 +0100 Subject: [PATCH 26/43] Move additional dependencies from private getters to constructor - Magento_Captcha --- .../Observer/CheckContactUsFormObserver.php | 65 ++++---- .../CheckContactUsFormObserverTest.php | 148 ++++++++++-------- 2 files changed, 110 insertions(+), 103 deletions(-) diff --git a/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php b/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php index 8c1da0e1ef104..2d0a6479bbcd6 100644 --- a/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php +++ b/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php @@ -3,34 +3,41 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Captcha\Observer; +use Magento\Captcha\Helper\Data; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\ActionFlag; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\App\Request\DataPersistorInterface; -use Magento\Framework\App\ObjectManager; +use Magento\Framework\Message\ManagerInterface; /** - * Class CheckContactUsFormObserver + * Check captcha on contact us form submit observer. */ class CheckContactUsFormObserver implements ObserverInterface { /** - * @var \Magento\Captcha\Helper\Data + * @var Data */ protected $_helper; /** - * @var \Magento\Framework\App\ActionFlag + * @var ActionFlag */ protected $_actionFlag; /** - * @var \Magento\Framework\Message\ManagerInterface + * @var ManagerInterface */ protected $messageManager; /** - * @var \Magento\Framework\App\Response\RedirectInterface + * @var RedirectInterface */ protected $redirect; @@ -45,60 +52,48 @@ class CheckContactUsFormObserver implements ObserverInterface private $dataPersistor; /** - * @param \Magento\Captcha\Helper\Data $helper - * @param \Magento\Framework\App\ActionFlag $actionFlag - * @param \Magento\Framework\Message\ManagerInterface $messageManager - * @param \Magento\Framework\App\Response\RedirectInterface $redirect + * @param Data $helper + * @param ActionFlag $actionFlag + * @param ManagerInterface $messageManager + * @param RedirectInterface $redirect * @param CaptchaStringResolver $captchaStringResolver + * @param DataPersistorInterface $dataPersistor */ public function __construct( - \Magento\Captcha\Helper\Data $helper, - \Magento\Framework\App\ActionFlag $actionFlag, - \Magento\Framework\Message\ManagerInterface $messageManager, - \Magento\Framework\App\Response\RedirectInterface $redirect, - CaptchaStringResolver $captchaStringResolver + Data $helper, + ActionFlag $actionFlag, + ManagerInterface $messageManager, + RedirectInterface $redirect, + CaptchaStringResolver $captchaStringResolver, + DataPersistorInterface $dataPersistor ) { $this->_helper = $helper; $this->_actionFlag = $actionFlag; $this->messageManager = $messageManager; $this->redirect = $redirect; $this->captchaStringResolver = $captchaStringResolver; + $this->dataPersistor = $dataPersistor; } /** * Check CAPTCHA on Contact Us page * - * @param \Magento\Framework\Event\Observer $observer + * @param Observer $observer * @return void */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { $formId = 'contact_us'; $captcha = $this->_helper->getCaptcha($formId); if ($captcha->isRequired()) { - /** @var \Magento\Framework\App\Action\Action $controller */ + /** @var Action $controller */ $controller = $observer->getControllerAction(); if (!$captcha->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId))) { $this->messageManager->addErrorMessage(__('Incorrect CAPTCHA.')); - $this->getDataPersistor()->set($formId, $controller->getRequest()->getPostValue()); - $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + $this->dataPersistor->set($formId, $controller->getRequest()->getPostValue()); + $this->_actionFlag->set('', Action::FLAG_NO_DISPATCH, true); $this->redirect->redirect($controller->getResponse(), 'contact/index/index'); } } } - - /** - * Get Data Persistor - * - * @return DataPersistorInterface - */ - private function getDataPersistor() - { - if ($this->dataPersistor === null) { - $this->dataPersistor = ObjectManager::getInstance() - ->get(DataPersistorInterface::class); - } - - return $this->dataPersistor; - } } diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php index 83bfb2910f9f8..6bb21e9432d70 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php @@ -5,94 +5,108 @@ */ namespace Magento\Captcha\Test\Unit\Observer; +use Magento\Captcha\Helper\Data; +use Magento\Captcha\Model\DefaultModel; +use Magento\Captcha\Observer\CaptchaStringResolver; +use Magento\Captcha\Observer\CheckContactUsFormObserver; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\ActionFlag; +use Magento\Framework\App\Request\DataPersistorInterface; +use Magento\Framework\App\Request\Http; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\Event\Observer; +use Magento\Framework\Message\ManagerInterface; +use Magento\Framework\Session\SessionManager; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + /** + * Test class for \Magento\Captcha\Observer\CheckContactUsFormObserver + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CheckContactUsFormObserverTest extends \PHPUnit\Framework\TestCase +class CheckContactUsFormObserverTest extends TestCase { /** - * @var \Magento\Captcha\Observer\CheckContactUsFormObserver + * @var ObjectManager */ - protected $checkContactUsFormObserver; + private $objectManagerHelper; /** - * @var \Magento\Captcha\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + * @var CheckContactUsFormObserver */ - protected $helperMock; + private $checkContactUsFormObserver; /** - * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject + * @var Data|MockObject */ - protected $actionFlagMock; + private $helperMock; - /* - * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + /** + * @var ActionFlag|MockObject */ - protected $messageManagerMock; + private $actionFlagMock; /** - * @var \Magento\Framework\App\Response\RedirectInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ManagerInterface|MockObject */ - protected $redirectMock; + private $messageManagerMock; /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + * @var RedirectInterface|MockObject */ - protected $objectManagerHelper; + private $redirectMock; /** - * @var \Magento\Captcha\Observer\CaptchaStringResolver|\PHPUnit_Framework_MockObject_MockObject + * @var CaptchaStringResolver|MockObject */ - protected $captchaStringResolverMock; + private $captchaStringResolverMock; /** - * @var \Magento\Framework\Session\SessionManager|\PHPUnit_Framework_MockObject_MockObject + * @var DataPersistorInterface|MockObject */ - protected $sessionMock; + private $dataPersistorMock; /** - * @var \Magento\Captcha\Model\DefaultModel|\PHPUnit_Framework_MockObject_MockObject + * @var SessionManager|MockObject */ - protected $captchaMock; + private $sessionMock; /** - * @var \Magento\Framework\App\Request\DataPersistorInterface|\PHPUnit_Framework_MockObject_MockObject + * @var DefaultModel|MockObject */ - protected $dataPersistorMock; + private $captchaMock; protected function setUp() { - $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->objectManagerHelper = new ObjectManager($this); + + $this->helperMock = $this->createMock(Data::class); + $this->actionFlagMock = $this->createMock(ActionFlag::class); + $this->messageManagerMock = $this->createMock(ManagerInterface::class); + $this->redirectMock = $this->createMock(RedirectInterface::class); + $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class); + $this->dataPersistorMock = $this->getMockBuilder(DataPersistorInterface::class) + ->getMockForAbstractClass(); - $this->helperMock = $this->createMock(\Magento\Captcha\Helper\Data::class); - $this->actionFlagMock = $this->createMock(\Magento\Framework\App\ActionFlag::class); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\ManagerInterface::class); - $this->redirectMock = $this->createMock(\Magento\Framework\App\Response\RedirectInterface::class); - $this->captchaStringResolverMock = $this->createMock(\Magento\Captcha\Observer\CaptchaStringResolver::class); $this->sessionMock = $this->createPartialMock( - \Magento\Framework\Session\SessionManager::class, + SessionManager::class, ['addErrorMessage'] ); - $this->dataPersistorMock = $this->getMockBuilder(\Magento\Framework\App\Request\DataPersistorInterface::class) - ->getMockForAbstractClass(); + $this->captchaMock = $this->createMock(DefaultModel::class); $this->checkContactUsFormObserver = $this->objectManagerHelper->getObject( - \Magento\Captcha\Observer\CheckContactUsFormObserver::class, + CheckContactUsFormObserver::class, [ 'helper' => $this->helperMock, 'actionFlag' => $this->actionFlagMock, 'messageManager' => $this->messageManagerMock, 'redirect' => $this->redirectMock, - 'captchaStringResolver' => $this->captchaStringResolverMock + 'captchaStringResolver' => $this->captchaStringResolverMock, + 'dataPersistor' => $this->dataPersistorMock ] ); - $this->objectManagerHelper->setBackwardCompatibleProperty( - $this->checkContactUsFormObserver, - 'dataPersistor', - $this->dataPersistorMock - ); - - $this->captchaMock = $this->createMock(\Magento\Captcha\Model\DefaultModel::class); } public function testCheckContactUsFormWhenCaptchaIsRequiredAndValid() @@ -100,14 +114,13 @@ public function testCheckContactUsFormWhenCaptchaIsRequiredAndValid() $formId = 'contact_us'; $captchaValue = 'some-value'; - $controller = $this->createMock(\Magento\Framework\App\Action\Action::class); - $request = $this->createMock(\Magento\Framework\App\Request\Http::class); - $request->expects($this->any()) - ->method('getPost') - ->with(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE, null) + $controller = $this->createMock(Action::class); + $request = $this->createMock(Http::class); + $request->method('getPost') + ->with(Data::INPUT_NAME_FIELD_VALUE, null) ->willReturn([$formId => $captchaValue]); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $this->captchaMock->expects($this->any())->method('isRequired')->willReturn(true); + $controller->method('getRequest')->willReturn($request); + $this->captchaMock->method('isRequired')->willReturn(true); $this->captchaMock->expects($this->once()) ->method('isCorrect') ->with($captchaValue) @@ -116,13 +129,13 @@ public function testCheckContactUsFormWhenCaptchaIsRequiredAndValid() ->method('resolve') ->with($request, $formId) ->willReturn($captchaValue); - $this->helperMock->expects($this->any()) - ->method('getCaptcha') - ->with($formId)->willReturn($this->captchaMock); + $this->helperMock->method('getCaptcha') + ->with($formId) + ->willReturn($this->captchaMock); $this->sessionMock->expects($this->never())->method('addErrorMessage'); $this->checkContactUsFormObserver->execute( - new \Magento\Framework\Event\Observer(['controller_action' => $controller]) + new Observer(['controller_action' => $controller]) ); } @@ -135,11 +148,10 @@ public function testCheckContactUsFormRedirectsCustomerWithWarningMessageWhenCap $redirectUrl = 'http://magento.com/contacts/'; $postData = ['name' => 'Some Name']; - $request = $this->createMock(\Magento\Framework\App\Request\Http::class); + $request = $this->createMock(Http::class); $response = $this->createMock(\Magento\Framework\App\Response\Http::class); - $request->expects($this->any()) - ->method('getPost') - ->with(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE, null) + $request->method('getPost') + ->with(Data::INPUT_NAME_FIELD_VALUE, null) ->willReturn([$formId => $captchaValue]); $request->expects($this->once()) ->method('getPostValue') @@ -150,10 +162,10 @@ public function testCheckContactUsFormRedirectsCustomerWithWarningMessageWhenCap ->with($response, $redirectRoutePath, []) ->willReturn($redirectUrl); - $controller = $this->createMock(\Magento\Framework\App\Action\Action::class); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $controller->expects($this->any())->method('getResponse')->willReturn($response); - $this->captchaMock->expects($this->any())->method('isRequired')->willReturn(true); + $controller = $this->createMock(Action::class); + $controller->method('getRequest')->willReturn($request); + $controller->method('getResponse')->willReturn($response); + $this->captchaMock->method('isRequired')->willReturn(true); $this->captchaMock->expects($this->once()) ->method('isCorrect') ->with($captchaValue) @@ -162,32 +174,32 @@ public function testCheckContactUsFormRedirectsCustomerWithWarningMessageWhenCap ->method('resolve') ->with($request, $formId) ->willReturn($captchaValue); - $this->helperMock->expects($this->any()) - ->method('getCaptcha') + $this->helperMock->method('getCaptcha') ->with($formId) ->willReturn($this->captchaMock); - $this->messageManagerMock->expects($this->once())->method('addErrorMessage')->with($warningMessage); + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with($warningMessage); $this->actionFlagMock->expects($this->once()) ->method('set') - ->with('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + ->with('', Action::FLAG_NO_DISPATCH, true); $this->dataPersistorMock->expects($this->once()) ->method('set') ->with($formId, $postData); $this->checkContactUsFormObserver->execute( - new \Magento\Framework\Event\Observer(['controller_action' => $controller]) + new Observer(['controller_action' => $controller]) ); } public function testCheckContactUsFormDoesNotCheckCaptchaWhenItIsNotRequired() { - $this->helperMock->expects($this->any()) - ->method('getCaptcha') + $this->helperMock->method('getCaptcha') ->with('contact_us') ->willReturn($this->captchaMock); - $this->captchaMock->expects($this->any())->method('isRequired')->willReturn(false); + $this->captchaMock->method('isRequired')->willReturn(false); $this->captchaMock->expects($this->never())->method('isCorrect'); - $this->checkContactUsFormObserver->execute(new \Magento\Framework\Event\Observer()); + $this->checkContactUsFormObserver->execute(new Observer()); } } From 2d19477ebf398f066930ac413e6e4ebec6ce1830 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Tue, 11 Feb 2020 17:00:37 +0200 Subject: [PATCH 27/43] fix static, fix conflict merge --- .../Magento/Catalog/Model/Product/Copier.php | 25 ++- .../Test/Unit/Model/Product/CopierTest.php | 174 +++++++++++------- 2 files changed, 118 insertions(+), 81 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Copier.php b/app/code/Magento/Catalog/Model/Product/Copier.php index 645977a35af1f..b04d3da8f0223 100644 --- a/app/code/Magento/Catalog/Model/Product/Copier.php +++ b/app/code/Magento/Catalog/Model/Product/Copier.php @@ -8,10 +8,12 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Option\Repository as OptionRepository; use Magento\Catalog\Model\ProductFactory; use Magento\Framework\App\ObjectManager; use Magento\Framework\EntityManager\MetadataPool; +use Magento\Store\Model\Store; use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException; /** @@ -72,20 +74,17 @@ public function __construct( /** * Create product duplicate * - * @param \Magento\Catalog\Model\Product $product - * - * @return \Magento\Catalog\Model\Product - * - * @throws \Exception + * @param Product $product + * @return Product */ - public function copy(Product $product) + public function copy(Product $product): Product { $product->getWebsiteIds(); $product->getCategoryIds(); $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - /** @var \Magento\Catalog\Model\Product $duplicate */ + /** @var Product $duplicate */ $duplicate = $this->productFactory->create(); $productData = $product->getData(); $productData = $this->removeStockItem($productData); @@ -96,11 +95,11 @@ public function copy(Product $product) $duplicate->setMetaDescription(null); $duplicate->setIsDuplicate(true); $duplicate->setOriginalLinkId($product->getData($metadata->getLinkField())); - $duplicate->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + $duplicate->setStatus(Status::STATUS_DISABLED); $duplicate->setCreatedAt(null); $duplicate->setUpdatedAt(null); $duplicate->setId(null); - $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); $this->copyConstructor->build($product, $duplicate); $this->setDefaultUrl($product, $duplicate); $this->setStoresUrl($product, $duplicate); @@ -118,11 +117,11 @@ public function copy(Product $product) */ private function setDefaultUrl(Product $product, Product $duplicate) : void { - $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); $resource = $product->getResource(); $attribute = $resource->getAttribute('url_key'); $productId = $product->getId(); - $urlKey = $resource->getAttributeRawValue($productId, 'url_key', \Magento\Store\Model\Store::DEFAULT_STORE_ID); + $urlKey = $resource->getAttributeRawValue($productId, 'url_key', Store::DEFAULT_STORE_ID); do { $urlKey = $this->modifyUrl($urlKey); $duplicate->setUrlKey($urlKey); @@ -175,7 +174,7 @@ private function setStoresUrl(Product $product, Product $duplicate) : void $productResource->saveAttribute($duplicate, 'url_path'); $productResource->saveAttribute($duplicate, 'url_key'); } - $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); } /** @@ -197,7 +196,7 @@ private function modifyUrl(string $urlKey) : string * @param array $productData * @return array */ - private function removeStockItem(array $productData) + private function removeStockItem(array $productData): array { if (isset($productData[ProductInterface::EXTENSION_ATTRIBUTES_KEY])) { $extensionAttributes = $productData[ProductInterface::EXTENSION_ATTRIBUTES_KEY]; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php index 18179489fbd94..91441890e83b1 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php @@ -3,53 +3,66 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Catalog\Test\Unit\Model\Product; use Magento\Catalog\Api\Data\ProductExtension; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Copier; +use Magento\Catalog\Model\Product\CopyConstructorInterface; +use Magento\Catalog\Model\Product\Option\Repository; +use Magento\Catalog\Model\ProductFactory; +use Magento\Catalog\Model\ResourceModel\Product as ProductResourceModel; use Magento\CatalogInventory\Api\Data\StockItemInterface; +use Magento\Eav\Model\Entity\AbstractEntity; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Framework\EntityManager\EntityMetadata; +use Magento\Framework\EntityManager\MetadataPool; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; /** * Test for Magento\Catalog\Model\Product\Copier class. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CopierTest extends \PHPUnit\Framework\TestCase +class CopierTest extends TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var Copier */ - private $optionRepositoryMock; + private $_model; /** - * @var Copier + * @var Repository|MockObject */ - private $_model; + private $optionRepositoryMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var CopyConstructorInterface|MockObject */ private $copyConstructorMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ProductFactory|MockObject */ private $productFactoryMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ScopeOverriddenValue|MockObject */ private $scopeOverriddenValueMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var Product|MockObject */ private $productMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var EntityMetadata|MockObject */ private $metadata; @@ -58,27 +71,23 @@ class CopierTest extends \PHPUnit\Framework\TestCase */ protected function setUp() { - $this->copyConstructorMock = $this->createMock(\Magento\Catalog\Model\Product\CopyConstructorInterface::class); - $this->productFactoryMock = $this->createPartialMock( - \Magento\Catalog\Model\ProductFactory::class, - ['create'] - ); - $this->scopeOverriddenValueMock = $this->createMock( - \Magento\Catalog\Model\Attribute\ScopeOverriddenValue::class - ); - $this->optionRepositoryMock = $this->createMock( - \Magento\Catalog\Model\Product\Option\Repository::class - ); + $this->copyConstructorMock = $this->createMock(CopyConstructorInterface::class); + $this->productFactoryMock = $this->createPartialMock(ProductFactory::class, ['create']); + $this->scopeOverriddenValueMock = $this->createMock(ScopeOverriddenValue::class); + $this->optionRepositoryMock = $this->createMock(Repository::class); $this->productMock = $this->createMock(Product::class); - $this->productMock->expects($this->any())->method('getEntityId')->willReturn(1); - $this->metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadata::class) + $this->metadata = $this->getMockBuilder(EntityMetadata::class) ->disableOriginalConstructor() ->getMock(); - $metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) + + /** @var MetadataPool|MockObject $metadataPool */ + $metadataPool = $this->getMockBuilder(MetadataPool::class) ->disableOriginalConstructor() ->getMock(); - $metadataPool->expects($this->any())->method('getMetadata')->willReturn($this->metadata); + $metadataPool->expects($this->once()) + ->method('getMetadata') + ->willReturn($this->metadata); $this->_model = new Copier( $this->copyConstructorMock, $this->productFactoryMock, @@ -89,9 +98,12 @@ protected function setUp() } /** + * Test duplicate product + * + * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function testCopy() + public function testCopy(): void { $stockItem = $this->createMock(StockItemInterface::class); $extensionAttributes = $this->getMockBuilder(ProductExtension::class) @@ -110,15 +122,19 @@ public function testCopy() 'product data' => ['product data'], ProductInterface::EXTENSION_ATTRIBUTES_KEY => $extensionAttributes, ]; - $this->productMock->expects($this->atLeastOnce())->method('getWebsiteIds'); - $this->productMock->expects($this->atLeastOnce())->method('getCategoryIds'); - $this->productMock->expects($this->any())->method('getData')->willReturnMap([ - ['', null, $productData], - ['linkField', null, '1'], - ]); + $this->productMock->expects($this->atLeastOnce()) + ->method('getWebsiteIds'); + $this->productMock->expects($this->atLeastOnce()) + ->method('getCategoryIds'); + $this->productMock->expects($this->exactly(2)) + ->method('getData') + ->willReturnMap([ + ['', null, $productData], + ['linkField', null, '1'], + ]); $entityMock = $this->getMockForAbstractClass( - \Magento\Eav\Model\Entity\AbstractEntity::class, + AbstractEntity::class, [], '', false, @@ -126,12 +142,12 @@ public function testCopy() true, ['checkAttributeUniqueValue'] ); - $entityMock->expects($this->any()) + $entityMock->expects($this->once()) ->method('checkAttributeUniqueValue') ->willReturn(true); $attributeMock = $this->getMockForAbstractClass( - \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class, + AbstractAttribute::class, [], '', false, @@ -139,22 +155,24 @@ public function testCopy() true, ['getEntity'] ); - $attributeMock->expects($this->any()) + $attributeMock->expects($this->once()) ->method('getEntity') ->willReturn($entityMock); - $resourceMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class) + $resourceMock = $this->getMockBuilder(ProductResourceModel::class) ->disableOriginalConstructor() ->setMethods(['getAttributeRawValue', 'duplicate', 'getAttribute']) ->getMock(); - $resourceMock->expects($this->any()) + $resourceMock->expects($this->once()) ->method('getAttributeRawValue') ->willReturn('urk-key-1'); - $resourceMock->expects($this->any()) + $resourceMock->expects($this->exactly(2)) ->method('getAttribute') ->willReturn($attributeMock); - $this->productMock->expects($this->any())->method('getResource')->will($this->returnValue($resourceMock)); + $this->productMock->expects($this->exactly(2)) + ->method('getResource') + ->willReturn($resourceMock); $duplicateMock = $this->createPartialMock( Product::class, @@ -176,51 +194,71 @@ public function testCopy() 'getStoreIds', 'setMetaTitle', 'setMetaKeyword', - 'setMetaDescription' + 'setMetaDescription', ] ); - $this->productFactoryMock->expects($this->once())->method('create')->will($this->returnValue($duplicateMock)); + $this->productFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($duplicateMock); $duplicateMock->expects($this->once())->method('setOptions')->with([]); $duplicateMock->expects($this->once())->method('setIsDuplicate')->with(true); $duplicateMock->expects($this->once())->method('setOriginalLinkId')->with(1); - $duplicateMock->expects( - $this->once() - )->method( - 'setStatus' - )->with( - \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED - ); + $duplicateMock->expects($this->once()) + ->method('setStatus') + ->with(Status::STATUS_DISABLED); $duplicateMock->expects($this->atLeastOnce())->method('setStoreId'); - $duplicateMock->expects($this->once())->method('setCreatedAt')->with(null); - $duplicateMock->expects($this->once())->method('setUpdatedAt')->with(null); - $duplicateMock->expects($this->once())->method('setId')->with(null); - $duplicateMock->expects($this->once())->method('setMetaTitle')->with(null); - $duplicateMock->expects($this->once())->method('setMetaKeyword')->with(null); - $duplicateMock->expects($this->once())->method('setMetaDescription')->with(null); - $duplicateMock->expects($this->atLeastOnce())->method('getStoreIds')->willReturn([]); - $duplicateMock->expects($this->atLeastOnce())->method('setData')->willReturn($duplicateMock); - $this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock); - $duplicateMock->expects($this->once())->method('setUrlKey')->with('urk-key-2')->willReturn($duplicateMock); - $duplicateMock->expects($this->once())->method('save'); - - $this->metadata->expects($this->any())->method('getLinkField')->willReturn('linkField'); - - $duplicateMock->expects($this->any())->method('getData')->willReturnMap([ - ['linkField', null, '2'], - ]); + $duplicateMock->expects($this->once()) + ->method('setCreatedAt') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setUpdatedAt') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setId') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setMetaTitle') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setMetaKeyword') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setMetaDescription') + ->with(null); + $duplicateMock->expects($this->atLeastOnce()) + ->method('getStoreIds')->willReturn([]); + $duplicateMock->expects($this->atLeastOnce()) + ->method('setData') + ->willReturn($duplicateMock); + $this->copyConstructorMock->expects($this->once()) + ->method('build') + ->with($this->productMock, $duplicateMock); + $duplicateMock->expects($this->once()) + ->method('setUrlKey') + ->with('urk-key-2') + ->willReturn($duplicateMock); + $duplicateMock->expects($this->once()) + ->method('save'); + $this->metadata->expects($this->once()) + ->method('getLinkField') + ->willReturn('linkField'); + $duplicateMock->expects($this->never()) + ->method('getData'); $this->optionRepositoryMock->expects($this->once()) ->method('duplicate') ->with($this->productMock, $duplicateMock); - $resourceMock->expects($this->once())->method('duplicate')->with(1, 2); $this->assertEquals($duplicateMock, $this->_model->copy($this->productMock)); } /** + * Test duplicate product with `UrlAlreadyExistsException` while copy stores url + * + * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl() + public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void { $stockItem = $this->getMockBuilder(StockItemInterface::class) ->getMock(); From a0e239a9fa8ce3ebc2a392b7a16442a24677ffdb Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal <k.tsymbal@atwix.com> Date: Wed, 12 Feb 2020 13:06:59 +0200 Subject: [PATCH 28/43] Unit test for Magento\Downloadable\Model\Sample\DeleteHandler --- .../Unit/Model/Sample/DeleteHandlerTest.php | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php new file mode 100644 index 0000000000000..b633c843138c5 --- /dev/null +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Downloadable\Test\Unit\Model\Sample; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product; +use Magento\Downloadable\Api\Data\SampleInterface; +use Magento\Downloadable\Api\SampleRepositoryInterface as SampleRepository; +use Magento\Downloadable\Model\Product\Type; +use Magento\Downloadable\Model\Sample\DeleteHandler; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit Test for \Magento\Downloadable\Model\Sample\DeleteHandler + */ +class DeleteHandlerTest extends TestCase +{ + const STUB_PRODUCT_TYPE = 'simple'; + const STUB_PRODUCT_SKU = 'sku'; + const STUB_SAMPLE_ID = 1; + + /** + * @var ProductInterface|MockObject + */ + private $entityMock; + + /** + * @var SampleRepository|MockObject + */ + private $sampleRepositoryMock; + + /** + * @var DeleteHandler + */ + private $deleteHandler; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->entityMock = $this->createMock(Product::class); + $this->sampleRepositoryMock = $this->getMockBuilder(SampleRepository::class) + ->disableOriginalConstructor() + ->setMethods(['getList', 'delete']) + ->getMockForAbstractClass(); + + $this->deleteHandler = (new ObjectManagerHelper($this))->getObject( + DeleteHandler::class, + ['sampleRepository' => $this->sampleRepositoryMock] + ); + } + + /** + * Test case when provided Product has type Downloadable. + */ + public function testExecuteWithDownloadableProduct() + { + $this->entityMock->expects($this->once()) + ->method('getTypeId') + ->willReturn(Type::TYPE_DOWNLOADABLE); + $this->entityMock->expects($this->once()) + ->method('getSku') + ->willReturn(self::STUB_PRODUCT_SKU); + + $sampleMock = $this->createMock(SampleInterface::class); + $sampleMock->expects($this->once()) + ->method('getId') + ->willReturn(self::STUB_SAMPLE_ID); + + $this->sampleRepositoryMock->expects($this->once())->method('delete'); + $this->sampleRepositoryMock->expects($this->once()) + ->method('getList') + ->willReturn([$sampleMock]); + + $this->assertSame($this->entityMock, $this->deleteHandler->execute($this->entityMock)); + } + + /** + * Test case when provided Product is not Downloadable. + */ + public function testExecuteWithOtherProduct() + { + $this->entityMock->expects($this->once()) + ->method('getTypeId') + ->willReturn(self::STUB_PRODUCT_TYPE); + + $this->sampleRepositoryMock->expects($this->never())->method('getList'); + $this->sampleRepositoryMock->expects($this->never())->method('delete'); + $this->assertSame($this->entityMock, $this->deleteHandler->execute($this->entityMock)); + } +} From 511e16a3ce006cb31621cb9b87cd576f0304c62b Mon Sep 17 00:00:00 2001 From: Nazar Klovanych <nazarn96@gmail.com> Date: Wed, 12 Feb 2020 14:59:27 +0200 Subject: [PATCH 29/43] refactor cover changes with unit test --- .../Customer/Model/Account/Redirect.php | 33 ++-- .../Test/Unit/Model/Account/RedirectTest.php | 182 +++++++++++++----- app/code/Magento/Customer/etc/di.xml | 0 3 files changed, 150 insertions(+), 65 deletions(-) mode change 100755 => 100644 app/code/Magento/Customer/Model/Account/Redirect.php mode change 100755 => 100644 app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php mode change 100755 => 100644 app/code/Magento/Customer/etc/di.xml diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php old mode 100755 new mode 100644 index ba1f72369f606..0389a380b36dc --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -7,19 +7,19 @@ use Magento\Customer\Model\Session; use Magento\Customer\Model\Url as CustomerUrl; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\Forward as ResultForward; +use Magento\Framework\Controller\Result\Redirect as ResultRedirect; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; +use Magento\Framework\Stdlib\CookieManagerInterface; +use Magento\Framework\Url\DecoderInterface; use Magento\Framework\Url\HostChecker; use Magento\Framework\UrlInterface; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\Controller\Result\Redirect as ResultRedirect; -use Magento\Framework\Controller\Result\Forward as ResultForward; -use Magento\Framework\Url\DecoderInterface; -use Magento\Framework\App\ObjectManager; -use Magento\Framework\Stdlib\CookieManagerInterface; /** * Account Redirect @@ -298,11 +298,14 @@ public function getRedirectCookie() */ public function setRedirectCookie($route) { - $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() - ->setHttpOnly(true) - ->setDuration(3600) - ->setPath($this->storeManager->getStore()->getStorePath()); - $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route, $cookieMetadata); + $this->getCookieManager()->setPublicCookie( + self::LOGIN_REDIRECT_URL, + $route, + $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setHttpOnly(true) + ->setDuration(3600) + ->setPath($this->storeManager->getStore()->getStorePath()) + ); } /** @@ -314,8 +317,10 @@ public function setRedirectCookie($route) */ public function clearRedirectCookie() { - $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() - ->setPath($this->storeManager->getStore()->getStorePath()); - $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL, $cookieMetadata); + $this->getCookieManager()->deleteCookie( + self::LOGIN_REDIRECT_URL, + $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setPath($this->storeManager->getStore()->getStorePath()) + ); } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php old mode 100755 new mode 100644 index f520182e51199..5c57012e0505c --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -8,18 +8,22 @@ namespace Magento\Customer\Test\Unit\Model\Account; -use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; +use Magento\Framework\Stdlib\Cookie\PublicCookieMetadata; +use Magento\Framework\Stdlib\CookieManagerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\Url\HostChecker; use Magento\Store\Model\ScopeInterface; +use PHPUnit\Framework\TestCase; +use PHPUnit\FrameworkMockObject\MockObject; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class RedirectTest extends \PHPUnit\Framework\TestCase +class RedirectTest extends TestCase { /** * @var Redirect @@ -27,74 +31,76 @@ class RedirectTest extends \PHPUnit\Framework\TestCase protected $model; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\RequestInterface + * @var MockObject|\Magento\Framework\App\RequestInterface */ protected $request; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Customer\Model\Session + * @var MockObject|\Magento\Customer\Model\Session */ protected $customerSession; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\Config\ScopeConfigInterface + * @var MockObject|\Magento\Framework\App\Config\ScopeConfigInterface */ protected $scopeConfig; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Store\Model\StoreManagerInterface + * @var MockObject|\Magento\Store\Model\StoreManagerInterface */ protected $storeManager; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Store\Model\Store + * @var MockObject|\Magento\Store\Model\Store */ protected $store; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\UrlInterface + * @var MockObject|\Magento\Framework\UrlInterface */ protected $url; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Url\DecoderInterface + * @var MockObject|\Magento\Framework\Url\DecoderInterface */ protected $urlDecoder; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Customer\Model\Url + * @var MockObject|\Magento\Customer\Model\Url */ protected $customerUrl; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Controller\Result\Redirect + * @var MockObject|\Magento\Framework\Controller\Result\Redirect */ protected $resultRedirect; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Controller\Result\Forward + * @var MockObject|\Magento\Framework\Controller\Result\Forward */ protected $resultForward; /** - * @var ResultFactory | \PHPUnit_Framework_MockObject_MockObject + * @var ResultFactory|MockObject */ protected $resultFactory; /** - * @var CookieMetadataFactory | \PHPUnit_Framework_MockObject_MockObject + * @var CookieMetadataFactory|MockObject */ protected $cookieMetadataFactory; /** - * @var HostChecker | \PHPUnit_Framework_MockObject_MockObject + * @var HostChecker|MockObject */ private $hostChecker; + /** + * @inheritdoc + */ protected function setUp() { $this->request = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class); - $this->customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class) ->disableOriginalConstructor() ->setMethods( @@ -117,44 +123,27 @@ protected function setUp() ->getMock(); $this->scopeConfig = $this->getMockForAbstractClass(\Magento\Framework\App\Config\ScopeConfigInterface::class); - - $this->store = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - + $this->store = $this->createMock(\Magento\Store\Model\Store::class); $this->storeManager = $this->getMockForAbstractClass(\Magento\Store\Model\StoreManagerInterface::class); - $this->storeManager->expects($this->once()) - ->method('getStore') - ->willReturn($this->store); - $this->url = $this->getMockForAbstractClass(\Magento\Framework\UrlInterface::class); $this->urlDecoder = $this->getMockForAbstractClass(\Magento\Framework\Url\DecoderInterface::class); - $this->customerUrl = $this->getMockBuilder(\Magento\Customer\Model\Url::class) - ->setMethods(['DashboardUrl', 'getAccountUrl', 'getLoginUrl', 'getLogoutUrl', 'getDashboardUrl']) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultRedirect = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultForward = $this->getMockBuilder(\Magento\Framework\Controller\Result\Forward::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultFactory = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->cookieMetadataFactory = $this->getMockBuilder(CookieMetadataFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->hostChecker = $this->getMockBuilder(HostChecker::class) - ->disableOriginalConstructor() + ->setMethods( + [ + 'DashboardUrl', + 'getAccountUrl', + 'getLoginUrl', + 'getLogoutUrl', + 'getDashboardUrl' + ] + )->disableOriginalConstructor() ->getMock(); + $this->resultRedirect = $this->createMock(\Magento\Framework\Controller\Result\Redirect::class); + $this->resultForward = $this->createMock(\Magento\Framework\Controller\Result\Forward::class); + $this->resultFactory = $this->createMock(\Magento\Framework\Controller\ResultFactory::class); + $this->cookieMetadataFactory = $this->createMock(CookieMetadataFactory::class); + $this->hostChecker = $this->createMock(HostChecker::class); $objectManager = new ObjectManager($this); $this->model = $objectManager->getObject( \Magento\Customer\Model\Account\Redirect::class, @@ -174,6 +163,8 @@ protected function setUp() } /** + * Verify get redirect method + * * @param int $customerId * @param int $lastCustomerId * @param string $referer @@ -214,6 +205,9 @@ public function testGetRedirect( ->willReturnSelf(); // Preparations for method prepareRedirectUrl() + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); $this->store->expects($this->once())->method('getBaseUrl')->willReturn($baseUrl); $this->customerSession->expects($this->any())->method('getBeforeAuthUrl')->willReturn($beforeAuthUrl); @@ -257,6 +251,8 @@ public function testGetRedirect( } /** + * Redirect data provider + * * @return array */ public function getRedirectDataProvider() @@ -305,7 +301,12 @@ public function getRedirectDataProvider() ]; } - public function testBeforeRequestParams() + /** + * Verify before request params + * + * @return void + */ + public function testBeforeRequestParams(): void { $requestParams = [ 'param1' => 'value1', @@ -315,6 +316,9 @@ public function testBeforeRequestParams() $controller = 'controller'; $action = 'action'; + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); $this->customerSession->expects($this->exactly(2)) ->method('getBeforeRequestParams') ->willReturn($requestParams); @@ -327,7 +331,6 @@ public function testBeforeRequestParams() $this->customerSession->expects($this->once()) ->method('getBeforeAction') ->willReturn($action); - $this->resultForward->expects($this->once()) ->method('setParams') ->with($requestParams) @@ -344,7 +347,6 @@ public function testBeforeRequestParams() ->method('forward') ->with($action) ->willReturnSelf(); - $this->resultFactory->expects($this->once()) ->method('create') ->with(ResultFactory::TYPE_FORWARD) @@ -353,4 +355,82 @@ public function testBeforeRequestParams() $result = $this->model->getRedirect(); $this->assertSame($this->resultForward, $result); } + + /** + * Verify set redirect cokkie method + * + * @return void + */ + public function testSetRedirectCookie(): void + { + $coockieManagerMock = $this->createMock(CookieManagerInterface::class); + $publicMetadataMock = $this->createMock(PublicCookieMetadata::class); + $routeMock = 'route'; + + $this->model->setCookieManager($coockieManagerMock); + + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); + $this->store->expects($this->once()) + ->method('getStorePath') + ->willReturn('storePath'); + $this->cookieMetadataFactory->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($publicMetadataMock); + $publicMetadataMock->expects($this->once()) + ->method('setHttpOnly') + ->with(true) + ->willReturnSelf(); + $publicMetadataMock->expects($this->once()) + ->method('setDuration') + ->with(3600) + ->willReturnSelf(); + $publicMetadataMock->expects($this->once()) + ->method('setPath') + ->with('storePath') + ->willReturnSelf(); + $coockieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->with( + Redirect::LOGIN_REDIRECT_URL, + $routeMock, + $publicMetadataMock + ); + $this->model->setRedirectCookie($routeMock); + } + + /** + * Verify clear redirect cookie + * + * @return void + */ + public function testClearRedirectCookie(): void + { + $coockieManagerMock = $this->createMock(CookieManagerInterface::class); + $publicMetadataMock = $this->createMock(PublicCookieMetadata::class); + + $this->model->setCookieManager($coockieManagerMock); + + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); + $this->store->expects($this->once()) + ->method('getStorePath') + ->willReturn('storePath'); + $this->cookieMetadataFactory->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($publicMetadataMock); + $publicMetadataMock->expects($this->once()) + ->method('setPath') + ->with('storePath') + ->willReturnSelf(); + $coockieManagerMock->expects($this->once()) + ->method('deleteCookie') + ->with( + Redirect::LOGIN_REDIRECT_URL, + $publicMetadataMock + ); + $this->model->clearRedirectCookie(); + } } diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml old mode 100755 new mode 100644 From fb0f0acc084fff95162ea806ca746c58e7c630a7 Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal <k.tsymbal@atwix.com> Date: Wed, 12 Feb 2020 15:15:20 +0200 Subject: [PATCH 30/43] Unit test for \Magento\MediaGallery\Plugin\Wysiwyg\Images\Storage --- .../Plugin/Wysiwyg/Images/StorageTest.php | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php diff --git a/app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php b/app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php new file mode 100644 index 0000000000000..0c653a9543b19 --- /dev/null +++ b/app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php @@ -0,0 +1,176 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\MediaGallery\Test\Unit\Plugin\Wysiwyg\Images; + +use Magento\Cms\Model\Wysiwyg\Images\Storage as StorageSubject; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\ReadInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\MediaGallery\Plugin\Wysiwyg\Images\Storage; +use Magento\MediaGalleryApi\Model\Asset\Command\DeleteByPathInterface; +use Magento\MediaGalleryApi\Model\Asset\Command\GetByPathInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; + +/** + * Unit test for \Magento\MediaGallery\Plugin\Wysiwyg\Images\Storage + */ +class StorageTest extends TestCase +{ + const STUB_TARGET = '/stub/test.png'; + const STUB_RELATIVE_PATH = 'test.png'; + + /** + * @var Storage + */ + private $storage; + + /** + * @var GetByPathInterface|MockObject + */ + private $getMediaAssetByPathMock; + + /** + * @var DeleteByPathInterface|MockObject + */ + private $deleteMediaAssetByPathMock; + + /** + * @var Filesystem|MockObject + */ + private $filesystemMock; + + /** + * @var LoggerInterface|MockObject + */ + private $loggerMock; + + /** + * @var StorageSubject|MockObject + */ + private $storageSubjectMock; + + /** + * @var ReadInterface|MockObject + */ + private $readInterfaceMock; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->storageSubjectMock = $this->createMock(StorageSubject::class); + $this->filesystemMock = $this->createMock(Filesystem::class); + $this->getMediaAssetByPathMock = $this->createMock(GetByPathInterface::class); + $this->deleteMediaAssetByPathMock = $this->getMockBuilder(DeleteByPathInterface::class) + ->disableOriginalConstructor() + ->setMethods(['execute']) + ->getMockForAbstractClass(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['critical']) + ->getMockForAbstractClass(); + $this->readInterfaceMock = $this->getMockBuilder(ReadInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getRelativePath']) + ->getMockForAbstractClass(); + + $this->storage = (new ObjectManagerHelper($this))->getObject( + Storage::class, + [ + 'getMediaAssetByPath' => $this->getMediaAssetByPathMock, + 'deleteMediaAssetByPath' => $this->deleteMediaAssetByPathMock, + 'filesystem' => $this->filesystemMock, + 'logger' => $this->loggerMock + ] + ); + } + + /** + * Test case when an exception is thrown during the method execution. + */ + public function testAfterDeleteFileExpectsDeleteMediaAssetExecuted() + { + $this->setupMocksToReturnCorrectRelativePath(); + $this->deleteMediaAssetByPathMock->expects($this->once())->method('execute'); + $this->loggerMock->expects($this->never())->method('critical'); + + $this->executeOriginalMethodWithCorrectTarget(); + } + + /** + * Test case when an exception is thrown during the method execution. + */ + public function testAfterDeleteFileWithException() + { + $this->setupMocksToReturnCorrectRelativePath(); + $this->deleteMediaAssetByPathMock->expects($this->once()) + ->method('execute') + ->willThrowException(new \Exception()); + $this->loggerMock->expects($this->once())->method('critical'); + + $this->executeOriginalMethodWithCorrectTarget(); + } + + /** + * Test case when the target is not a string. + */ + public function testAfterDeleteFileWhenTargetIsNotString() + { + $target = []; + $this->filesystemMock->expects($this->never())->method('getDirectoryRead'); + $this->deleteMediaAssetByPathMock->expects($this->never())->method('execute'); + $this->assertSame( + $this->storageSubjectMock, + $this->storage->afterDeleteFile($this->storageSubjectMock, $this->storageSubjectMock, $target) + ); + } + + /** + * Test case when there is no Relative Path which is need to be deleted. + */ + public function testAfterDeleteFileWhenRelativePathIsEmpty() + { + $this->readInterfaceMock->expects($this->once()) + ->method('getRelativePath') + ->willReturn(''); + $this->filesystemMock->expects($this->once()) + ->method('getDirectoryRead') + ->willReturn($this->readInterfaceMock); + + $this->deleteMediaAssetByPathMock->expects($this->never())->method('execute'); + $this->executeOriginalMethodWithCorrectTarget(); + } + + /** + * Call the tested method + */ + private function executeOriginalMethodWithCorrectTarget() + { + $this->assertSame( + $this->storageSubjectMock, + $this->storage->afterDeleteFile($this->storageSubjectMock, $this->storageSubjectMock, self::STUB_TARGET) + ); + } + + /** + * Set mocks in order to return the relative path + */ + private function setupMocksToReturnCorrectRelativePath() + { + $this->readInterfaceMock->expects($this->once()) + ->method('getRelativePath') + ->willReturn(self::STUB_RELATIVE_PATH); + $this->filesystemMock->expects($this->once()) + ->method('getDirectoryRead') + ->willReturn($this->readInterfaceMock); + } +} From 88a5e35d3642cdfe03097f594c42d691548cca05 Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal <k.tsymbal@atwix.com> Date: Wed, 12 Feb 2020 16:52:27 +0200 Subject: [PATCH 31/43] Unit Tests for observers from Magento_Reports --- .../SendfriendProductObserverTest.php | 93 +++++++++++++++++++ .../WishlistAddProductObserverTest.php | 93 +++++++++++++++++++ .../Observer/WishlistShareObserverTest.php | 93 +++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php create mode 100644 app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php create mode 100644 app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php diff --git a/app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php b/app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php new file mode 100644 index 0000000000000..88c30ec5bc236 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Reports\Test\Unit\Observer; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Reports\Model\Event; +use Magento\Reports\Model\ReportStatus; +use Magento\Reports\Observer\EventSaver; +use Magento\Reports\Observer\SendfriendProductObserver; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit test for \Magento\Reports\Observer\SendfriendProductObserver + */ +class SendfriendProductObserverTest extends TestCase +{ + /** + * @var Observer|MockObject + */ + private $eventObserverMock; + + /** + * @var EventSaver|MockObject + */ + private $eventSaverMock; + + /** + * @var ReportStatus|MockObject + */ + private $reportStatusMock; + + /** + * @var SendfriendProductObserver + */ + private $observer; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->eventObserverMock = $this->createMock(Observer::class); + $this->eventSaverMock = $this->createMock(EventSaver::class); + $this->reportStatusMock = $this->createMock(ReportStatus::class); + + $this->observer = (new ObjectManagerHelper($this))->getObject( + SendfriendProductObserver::class, + ['eventSaver' => $this->eventSaverMock, 'reportStatus' => $this->reportStatusMock] + ); + } + + /** + * Test case when report is disabled in config. + */ + public function testExecuteWhenReportIsDisabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_SEND) + ->willReturn(false); + + $this->eventSaverMock->expects($this->never())->method('save'); + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when report is enabled in config. + */ + public function testExecuteWhenReportIsEnabled() + { + $eventMock = $this->createPartialMock(Event::class, ['getProduct']); + $eventMock->expects($this->once()) + ->method('getProduct') + ->willReturn($this->createMock(ProductInterface::class)); + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_SEND) + ->willReturn(true); + $this->eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock); + + $this->eventSaverMock->expects($this->once())->method('save'); + $this->observer->execute($this->eventObserverMock); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php b/app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php new file mode 100644 index 0000000000000..5b282bb60ece2 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Reports\Test\Unit\Observer; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Reports\Model\Event; +use Magento\Reports\Model\ReportStatus; +use Magento\Reports\Observer\EventSaver; +use Magento\Reports\Observer\WishlistAddProductObserver; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit test for \Magento\Reports\Observer\WishlistAddProductObserver + */ +class WishlistAddProductObserverTest extends TestCase +{ + /** + * @var Observer|MockObject + */ + private $eventObserverMock; + + /** + * @var EventSaver|MockObject + */ + private $eventSaverMock; + + /** + * @var ReportStatus|MockObject + */ + private $reportStatusMock; + + /** + * @var WishlistAddProductObserver + */ + private $observer; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->eventObserverMock = $this->createMock(Observer::class); + $this->eventSaverMock = $this->createMock(EventSaver::class); + $this->reportStatusMock = $this->createMock(ReportStatus::class); + + $this->observer = (new ObjectManagerHelper($this))->getObject( + WishlistAddProductObserver::class, + ['eventSaver' => $this->eventSaverMock, 'reportStatus' => $this->reportStatusMock] + ); + } + + /** + * Test case when report is disabled in config. + */ + public function testExecuteWhenReportIsDisabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_TO_WISHLIST) + ->willReturn(false); + $this->eventSaverMock->expects($this->never())->method('save'); + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when report is enabled in config. + */ + public function testExecuteWhenReportIsEnabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_TO_WISHLIST) + ->willReturn(true); + + $eventMock = $this->createPartialMock(Event::class, ['getProduct']); + $eventMock->expects($this->once()) + ->method('getProduct') + ->willReturn($this->createMock(ProductInterface::class)); + $this->eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock); + + $this->eventSaverMock->expects($this->once())->method('save'); + $this->observer->execute($this->eventObserverMock); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php b/app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php new file mode 100644 index 0000000000000..d432fe013b138 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Reports\Test\Unit\Observer; + +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Reports\Model\Event; +use Magento\Reports\Model\ReportStatus; +use Magento\Reports\Observer\EventSaver; +use Magento\Reports\Observer\WishlistShareObserver; +use Magento\Wishlist\Model\Wishlist; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit test for \Magento\Reports\Observer\WishlistShareObserver + */ +class WishlistShareObserverTest extends TestCase +{ + /** + * @var Observer|MockObject + */ + private $eventObserverMock; + + /** + * @var EventSaver|MockObject + */ + private $eventSaverMock; + + /** + * @var ReportStatus|MockObject + */ + private $reportStatusMock; + + /** + * @var WishlistShareObserver + */ + private $observer; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->eventObserverMock = $this->createMock(Observer::class); + $this->eventSaverMock = $this->createMock(EventSaver::class); + $this->reportStatusMock = $this->createMock(ReportStatus::class); + + $this->observer = (new ObjectManagerHelper($this))->getObject( + WishlistShareObserver::class, + ['eventSaver' => $this->eventSaverMock, 'reportStatus' => $this->reportStatusMock] + ); + } + + /** + * Test case when report is disabled in config. + */ + public function testExecuteWhenReportIsDisabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_WISHLIST_SHARE) + ->willReturn(false); + $this->eventSaverMock->expects($this->never())->method('save'); + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when report is enabled in config. + */ + public function testExecuteWhenReportIsEnabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_WISHLIST_SHARE) + ->willReturn(true); + + $eventMock = $this->createPartialMock(Event::class, ['getWishlist']); + $eventMock->expects($this->once()) + ->method('getWishlist') + ->willReturn($this->createMock(Wishlist::class)); + $this->eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock); + + $this->eventSaverMock->expects($this->once())->method('save'); + $this->observer->execute($this->eventObserverMock); + } +} From 05256c8f9f61ffbd7a25b78be9decefe13c3f29f Mon Sep 17 00:00:00 2001 From: Alex Taranovsky <firster@atwix.com> Date: Wed, 12 Feb 2020 18:41:05 +0200 Subject: [PATCH 32/43] magento/magento2#: GraphQL. setPaymentMethodOnCart mutation. Extend list of required parameters for testSetPaymentMethodWithoutRequiredParameters. --- .../GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php | 4 ++++ .../GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php index 57aeda3295268..74f8e3c2e37dd 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php @@ -233,6 +233,10 @@ public function testSetDisabledPaymentOnCart() public function dataProviderSetPaymentMethodWithoutRequiredParameters(): array { return [ + 'missed_cart_id' => [ + 'cart_id: "", payment_method: {code: "' . Checkmo::PAYMENT_METHOD_CHECKMO_CODE . '"}', + 'Required parameter "cart_id" is missing.' + ], 'missed_payment_method_code' => [ 'cart_id: "cart_id_value", payment_method: {code: ""}', 'Required parameter "code" for "payment_method" is missing.' diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php index c3e35f0bf80e8..08c7bdd8dbc52 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php @@ -183,6 +183,10 @@ public function testSetPaymentMethodWithoutRequiredParameters(string $input, str public function dataProviderSetPaymentMethodWithoutRequiredParameters(): array { return [ + 'missed_cart_id' => [ + 'cart_id: "", payment_method: {code: "' . Checkmo::PAYMENT_METHOD_CHECKMO_CODE . '"}', + 'Required parameter "cart_id" is missing.' + ], 'missed_payment_method_code' => [ 'cart_id: "cart_id_value", payment_method: {code: ""}', 'Required parameter "code" for "payment_method" is missing.' From bab4fb677ea110d614d434937264fc107ac75c1d Mon Sep 17 00:00:00 2001 From: "Vincent.Le" <vinh.le2@niteco.se> Date: Thu, 13 Feb 2020 17:46:23 +0700 Subject: [PATCH 33/43] Issue/26843: Fix es_US Spanish (United States ) Locale is not supported in Magento 2.3.4 #26843 --- lib/internal/Magento/Framework/Locale/Config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/Locale/Config.php b/lib/internal/Magento/Framework/Locale/Config.php index c2d0147c7fdc8..08f66e25be773 100644 --- a/lib/internal/Magento/Framework/Locale/Config.php +++ b/lib/internal/Magento/Framework/Locale/Config.php @@ -108,6 +108,7 @@ class Config implements \Magento\Framework\Locale\ConfigInterface 'es_VE', /*Spanish (Venezuela)*/ 'en_IE', /*English (Ireland)*/ 'es_BO', /*Spanish (Bolivia)*/ + 'es_US', /*Spanish (United States)*/ ]; /** From 66d2cbcfb0f2f8f1d83c515cdc869a7fbfafdd85 Mon Sep 17 00:00:00 2001 From: engcom-Echo <engcom-vendorworker-echo@adobe.com> Date: Wed, 12 Feb 2020 11:39:10 +0200 Subject: [PATCH 34/43] Cover change tests, fix static --- .../Framework/Filesystem/Driver/FileTest.php | 34 ++++++- .../Framework/Filesystem/Io/FileTest.php | 92 +++++++++++++++++++ .../Framework/Filesystem/Driver/File.php | 8 +- .../Framework/Filesystem/Driver/Http.php | 11 ++- .../Magento/Framework/Filesystem/Io/File.php | 31 +++++-- .../Filesystem/Test/Unit/Driver/HttpTest.php | 88 +++++++++++++++--- 6 files changed, 233 insertions(+), 31 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php index 5f53e62165502..c8719ea7e0a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php @@ -5,11 +5,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Framework\Filesystem\Driver; use Magento\Framework\Exception\FileSystemException; +use PHPUnit\Framework\TestCase; -class FileTest extends \PHPUnit\Framework\TestCase +/** + * Verify File class + */ +class FileTest extends TestCase { /** * @var File @@ -50,16 +56,20 @@ public function setUp() /** * @inheritdoc + * + * @return void */ - protected function tearDown() + protected function tearDown(): void { $this->removeGeneratedDirectory(); } /** * Tests directory recursive read. + * + * @return void */ - public function testReadDirectoryRecursively() + public function testReadDirectoryRecursively(): void { $paths = [ 'foo/bar', @@ -77,9 +87,10 @@ public function testReadDirectoryRecursively() /** * Tests directory reading exception. * + * @return void * @expectedException \Magento\Framework\Exception\FileSystemException */ - public function testReadDirectoryRecursivelyFailure() + public function testReadDirectoryRecursivelyFailure(): void { $this->driver->readDirectoryRecursively($this->getTestPath('not-existing-directory')); } @@ -88,8 +99,9 @@ public function testReadDirectoryRecursivelyFailure() * Tests of directory creating. * * @throws FileSystemException + * @return void */ - public function testCreateDirectory() + public function testCreateDirectory(): void { $generatedPath = $this->getTestPath('generated/roo/bar/baz/foo'); $generatedPathBase = $this->getTestPath('generated'); @@ -123,6 +135,18 @@ public function testSymlinks(): void self::assertTrue($this->driver->deleteDirectory($linkName)); } + /** + * Verify file put content without content. + * + * @return void + * @throws FileSystemException + */ + public function testFilePutWithoutContents(): void + { + $path = $this->absolutePath . 'foo/file_three.txt'; + $this->assertEquals(0, $this->driver->filePutContents($path, '')); + } + /** * Remove generated directories. * diff --git a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php new file mode 100644 index 0000000000000..39503ec87f8e6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Test for \Magento\Framework\Filesystem\Io\File + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Filesystem\Io; + +use Magento\Framework\Exception\FileSystemException; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Verify filesystem client + */ +class FileTest extends TestCase +{ + + /** + * @var File + */ + private $io; + + /** + * @var String + */ + private $absolutePath; + + /** + * @var String + */ + private $generatedPath; + + /** + * @inheritDoc + */ + public function setUp() + { + $this->io = new File(); + $this->absolutePath = Bootstrap::getInstance()->getAppTempDir(); + $this->generatedPath = $this->getTestPath('/rollback_test_'); + $this->io->mkdir($this->generatedPath); + } + + /** + * @inheritdoc + * + * @return void + */ + protected function tearDown(): void + { + $this->removeGeneratedDirectory(); + } + + /** + * Verify file put without content. + * + * @return void + */ + public function testWrite(): void + { + $path = $this->generatedPath . '/file_three.txt'; + $this->assertEquals(0, $this->io->write($path, '', 0444)); + $this->assertEquals(false, is_writable($path)); + } + + /** + * Returns relative path for the test. + * + * @param $relativePath + * @return string + */ + protected function getTestPath($relativePath): string + { + return $this->absolutePath . $relativePath . time(); + } + + /** + * Remove generated directories. + * + * @return void + */ + private function removeGeneratedDirectory(): void + { + if (is_dir($this->generatedPath)) { + $this->io->rmdir($this->generatedPath, true); + } + } +} diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index 3251f5af1bad3..4d5ba7a1918ce 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -13,9 +13,8 @@ use Magento\Framework\Filesystem\Glob; /** - * Class File + * Driver file class * - * @package Magento\Framework\Filesystem\Driver * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class File implements DriverInterface @@ -593,12 +592,15 @@ public function fileOpen($path, $mode) */ public function fileReadLine($resource, $length, $ending = null) { + // phpcs:disable $result = @stream_get_line($resource, $length, $ending); + // phpcs:enable if (false === $result) { throw new FileSystemException( new \Magento\Framework\Phrase('File cannot be read %1', [$this->getWarningMessage()]) ); } + return $result; } @@ -976,7 +978,7 @@ public function getRealPathSafety($path) //Removing redundant directory separators. $path = preg_replace( - '/\\' .DIRECTORY_SEPARATOR .'\\' .DIRECTORY_SEPARATOR .'+/', + '/\\' . DIRECTORY_SEPARATOR . '\\' . DIRECTORY_SEPARATOR . '+/', DIRECTORY_SEPARATOR, $path ); diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php index 9f76bb33335d3..0191d5d8a3040 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php @@ -11,7 +11,7 @@ use Magento\Framework\Exception\FileSystemException; /** - * Class Http + * Http driver file class. */ class Http extends File { @@ -196,8 +196,13 @@ public function fileOpen($path, $mode) */ public function fileReadLine($resource, $length, $ending = null) { - $result = @stream_get_line($resource, $length, $ending); - + try { + $result = @stream_get_line($resource, $length, $ending); + } catch (\Exception $e) { + throw new FileSystemException( + new \Magento\Framework\Phrase('Stream get line failed %1', [$e->getMessage()]) + ); + } return $result; } diff --git a/lib/internal/Magento/Framework/Filesystem/Io/File.php b/lib/internal/Magento/Framework/Filesystem/Io/File.php index 97b121beb42c2..2e81325c8ec57 100644 --- a/lib/internal/Magento/Framework/Filesystem/Io/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Io/File.php @@ -3,10 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\Filesystem\Io; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; + /** * Filesystem client + * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class File extends AbstractIo @@ -186,7 +191,7 @@ public function streamWriteCsv(array $row, $delimiter = ',', $enclosure = '"') * Security enhancement for CSV data processing by Excel-like applications. * @see https://bugzilla.mozilla.org/show_bug.cgi?id=1054702 * - * @var $value string|\Magento\Framework\Phrase + * @var $value string|Phrase */ foreach ($row as $key => $value) { if (!is_string($value)) { @@ -201,6 +206,7 @@ public function streamWriteCsv(array $row, $delimiter = ',', $enclosure = '"') /** * Close an open file pointer + * * Set chmod on a file * * @return bool @@ -328,6 +334,7 @@ public function rmdir($dir, $recursive = false) /** * Delete a directory recursively + * * @param string $dir * @param bool $recursive * @return bool @@ -405,8 +412,8 @@ public function pwd() * * @param string $dir * @return true - * @throws \Exception * @SuppressWarnings(PHPMD.ShortMethodName) + * @throws LocalizedException */ public function cd($dir) { @@ -415,7 +422,9 @@ public function cd($dir) $this->_cwd = realpath($dir); return true; } else { - throw new \Exception('Unable to list current working directory.'); + throw new LocalizedException( + new Phrase('Unable to list current working directory.') + ); } } @@ -553,7 +562,7 @@ public function createDestinationDir($path) * @param string $folder * @param int $mode * @return true - * @throws \Exception + * @throws LocalizedException */ public function checkAndCreateFolder($folder, $mode = 0777) { @@ -564,7 +573,9 @@ public function checkAndCreateFolder($folder, $mode = 0777) $this->checkAndCreateFolder(dirname($folder), $mode); } if (!is_dir($folder) && !$this->mkdir($folder, $mode)) { - throw new \Exception("Unable to create directory '{$folder}'. Access forbidden."); + throw new LocalizedException( + new Phrase("Unable to create directory '{$folder}'. Access forbidden.") + ); } return true; } @@ -672,7 +683,7 @@ public static function chmodRecursive($dir, $mode) * * @param string|null $grep * @return array - * @throws \Exception + * @throws LocalizedException * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.ShortMethodName) */ @@ -685,7 +696,9 @@ public function ls($grep = null) } elseif (is_dir($this->_iwd)) { $dir = $this->_iwd; } else { - throw new \Exception('Unable to list current working directory.'); + throw new LocalizedException( + new Phrase('Unable to list current working directory.') + ); } $list = []; @@ -742,7 +755,9 @@ public function ls($grep = null) } closedir($dirHandler); } else { - throw new \Exception('Unable to list current working directory. Access forbidden.'); + throw new LocalizedException( + new Phrase('Unable to list current working directory. Access forbidden.') + ); } return $list; diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php index 8fc57f458334e..a851d30ef930e 100644 --- a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php @@ -3,12 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Framework\Filesystem\Test\Unit\Driver; -use \Magento\Framework\Filesystem\Driver\Http; +use Magento\Framework\Filesystem\Driver\Http; +use PHPUnit\Framework\TestCase; -class HttpTest extends \PHPUnit\Framework\TestCase +/** + * Verify HttpTest class. + */ +class HttpTest extends TestCase { /** @var array Result of get_headers() function */ public static $headers; @@ -22,6 +27,9 @@ class HttpTest extends \PHPUnit\Framework\TestCase /** @var bool Result of fsockopen() function */ public static $fsockopen; + /** + * @inheritDoc + */ protected function setUp() { require_once __DIR__ . '/../_files/http_mock.php'; @@ -33,35 +41,49 @@ protected function setUp() } /** + * Verify IsExists. + * + * @param string $status + * @param bool $result * @dataProvider dataProviderForTestIsExists + * @return void */ - public function testIsExists($status, $result) + public function testIsExists(string $status, bool $result): void { self::$headers = [$status]; $this->assertEquals($result, (new Http())->isExists('')); } /** + * Data provider fot test IsExists. + * * @return array */ - public function dataProviderForTestIsExists() + public function dataProviderForTestIsExists(): array { return [['200 OK', true], ['404 Not Found', false]]; } /** + * Verify Stat. + * + * @param array $headers + * @param array $result * @dataProvider dataProviderForTestStat + * @return void */ - public function testStat($headers, $result) + public function testStat(array $headers, array $result): void { self::$headers = $headers; $this->assertEquals($result, (new Http())->stat('')); } /** + * Data provider for test Stat. + * * @return array */ - public function dataProviderForTestStat() + public function dataProviderForTestStat(): array { $headers1 = [ 'Content-Length' => 128, @@ -106,45 +128,87 @@ protected function _resultForStat($nonEmptyValues = []) return array_merge($result, $nonEmptyValues); } - public function testFileGetContents() + /** + * Verify File get contents. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFileGetContents(): void { $content = 'some content'; self::$fileGetContents = $content; $this->assertEquals($content, (new Http())->fileGetContents('')); } - public function testFileGetContentsNoContent() + /** + * Verify File get contents without content. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFileGetContentsNoContent(): void { $content = ''; self::$fileGetContents = ''; $this->assertEquals($content, (new Http())->fileGetContents('')); } - public function testFilePutContents() + /** + * Verify File put contents. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFilePutContents(): void { self::$filePutContents = true; $this->assertTrue((new Http())->filePutContents('', '')); } /** + * Verify file put contents without content. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFilePutContentsNoContent(): void + { + self::$filePutContents = 0; + $this->assertEquals(0, (new Http())->filePutContents('', '')); + } + + /** + * Verify File put contents if is fail. + * * @expectedException \Magento\Framework\Exception\FileSystemException + * @return void */ - public function testFilePutContentsFail() + public function testFilePutContentsFail(): void { self::$filePutContents = false; (new Http())->filePutContents('', ''); } /** + * Verify File open invalid url. + * * @expectedException \Magento\Framework\Exception\FileSystemException * @expectedExceptionMessage The download URL is incorrect. Verify and try again. + * @return void */ - public function testFileOpenInvalidUrl() + public function testFileOpenInvalidUrl(): void { (new Http())->fileOpen('', ''); } - public function testFileOpen() + /** + * Verify File open. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFileOpen(): void { $fsockopenResult = 'resource'; self::$fsockopen = $fsockopenResult; From 205ee0facfc285eb3106f75c0cb40898526c3239 Mon Sep 17 00:00:00 2001 From: Vitalii Zabaznov <vzabaznov@magento.com> Date: Thu, 13 Feb 2020 13:24:08 -0600 Subject: [PATCH 35/43] MC-31499: [2.4] Re: Magento 2.3.4 | serious issues with local storage if custom sections.xml invalidations are active --- .../CustomerData/SectionConfigConverter.php | 17 ++++-- .../SectionConfigConverterTest.php | 54 +++++++++++++++++-- .../Unit/CustomerData/_files/sections.xml | 50 ++++++++++++++++- .../Unit/CustomerData/_files/sections2.xml | 40 ++++++++++++++ .../Customer/etc/frontend/sections.xml | 16 ++++-- .../Directory/etc/frontend/sections.xml | 4 +- .../Magento/Store/etc/frontend/sections.xml | 8 ++- 7 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections2.xml diff --git a/app/code/Magento/Customer/CustomerData/SectionConfigConverter.php b/app/code/Magento/Customer/CustomerData/SectionConfigConverter.php index 5f4bbb03d3936..c9a93c708e348 100644 --- a/app/code/Magento/Customer/CustomerData/SectionConfigConverter.php +++ b/app/code/Magento/Customer/CustomerData/SectionConfigConverter.php @@ -5,6 +5,9 @@ */ namespace Magento\Customer\CustomerData; +/** + * Class that receives xml merged source and process it. + */ class SectionConfigConverter implements \Magento\Framework\Config\ConverterInterface { /** @@ -13,7 +16,7 @@ class SectionConfigConverter implements \Magento\Framework\Config\ConverterInter const INVALIDATE_ALL_SECTIONS_MARKER = '*'; /** - * {@inheritdoc} + * @inheritdoc */ public function convert($source) { @@ -21,10 +24,18 @@ public function convert($source) foreach ($source->getElementsByTagName('action') as $action) { $actionName = strtolower($action->getAttribute('name')); foreach ($action->getElementsByTagName('section') as $section) { - $sections[$actionName][] = strtolower($section->getAttribute('name')); + $sectionName = strtolower($section->getAttribute('name')); + + if ($sectionName === self::INVALIDATE_ALL_SECTIONS_MARKER) { + $sections[$actionName] = []; + $sections[$actionName][] = self::INVALIDATE_ALL_SECTIONS_MARKER; + break; + } else { + $sections[$actionName][] = $sectionName; + } } if (!isset($sections[$actionName])) { - $sections[$actionName] = self::INVALIDATE_ALL_SECTIONS_MARKER; + $sections[$actionName][] = self::INVALIDATE_ALL_SECTIONS_MARKER; } } return [ diff --git a/app/code/Magento/Customer/Test/Unit/CustomerData/SectionConfigConverterTest.php b/app/code/Magento/Customer/Test/Unit/CustomerData/SectionConfigConverterTest.php index bc1085e295995..b78aa8609607e 100644 --- a/app/code/Magento/Customer/Test/Unit/CustomerData/SectionConfigConverterTest.php +++ b/app/code/Magento/Customer/Test/Unit/CustomerData/SectionConfigConverterTest.php @@ -6,6 +6,7 @@ namespace Magento\Customer\Test\Unit\CustomerData; +use Magento\Framework\App\Arguments\ValidationState; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; class SectionConfigConverterTest extends \PHPUnit\Framework\TestCase @@ -19,6 +20,12 @@ class SectionConfigConverterTest extends \PHPUnit\Framework\TestCase /** @var \DOMDocument */ protected $source; + /** @var \Magento\Framework\Config\Dom config merger */ + private $configMergerClass; + + /** @var ValidationState */ + private $validationStateMock; + protected function setUp() { $this->source = new \DOMDocument(); @@ -26,20 +33,61 @@ protected function setUp() $this->converter = $this->objectManagerHelper->getObject( \Magento\Customer\CustomerData\SectionConfigConverter::class ); + $this->validationStateMock = $this->createMock(ValidationState::class); + } + + /** + * Return newly created instance of a config merger + * + * @param string $mergerClass + * @param string $initialContents + * @return \Magento\Framework\Config\Dom + * @throws \UnexpectedValueException + */ + private function createConfig($mergerClass, $initialContents) + { + $this->validationStateMock->method('isValidationRequired')->willReturn(\false); + return new $mergerClass( + $initialContents, + $this->validationStateMock, + [ + '/config/action' => 'name', + '/config/action/section' => 'name', + ], + null, + null + ); } public function testConvert() { $this->source->loadXML(file_get_contents(__DIR__ . '/_files/sections.xml')); + $this->configMergerClass = $this->createConfig( + 'Magento\Framework\Config\Dom', + file_get_contents(__DIR__ . '/_files/sections.xml') + ); + + $this->configMergerClass->merge(file_get_contents(__DIR__ . '/_files/sections2.xml')); + $this->assertEquals( [ 'sections' => [ - 'customer/account/logout' => '*', - 'customer/account/editpost' => ['account'], + 'sales/guest/reorder' => ['account'], + 'sales/order/reorder' => ['account', 'cart'], + 'stores/store/switch' => ['*'], + 'directory/currency/switch' => ['*'], + 'customer/account/logout' => ['account', 'cart'], + 'customer/account/editpost' => ['account', 'acc', 'cart'], + 'checkout/cart/delete' => ['*'], + 'customer/account/createpost' => ['*'], + 'catalog/product_compare/add' => ['*'], + 'catalog/product_compare/remove' => ['account', 'acc'], + 'catalog/product_compare/clear' => ['*'], + 'checkout/cart/add' => ['*'], ], ], - $this->converter->convert($this->source) + $this->converter->convert($this->configMergerClass->getDom()) ); } } diff --git a/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections.xml b/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections.xml index 0b4250f678a68..fac1ef42c8a67 100644 --- a/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections.xml +++ b/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections.xml @@ -7,8 +7,56 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> - <action name="customer/account/logout"/> + <!-- Actions 1-4 are specified in sections.xml file only --> + <!-- 1 - Action has one Section --> + <action name="sales/guest/reorder"> + <section name="account"/> + </action> + <!-- 2 - Action has two Sections --> + <action name="sales/order/reorder"> + <section name="account"/> + <section name="cart"/> + </action> + <!-- 3 - Action has two Sections and "*" --> + <action name="stores/store/switch"> + <section name="account"/> + <section name="*"/> + <section name="cart"/> + </action> + <!-- 4 - Action has "empty_section" --> + <action name="directory/currency/switch"/> + <!-- Actions 5-12 are specified in files sections.xml and sections2.xml for merging --> + <!-- 5 - Action in both files has unique Section --> + <action name="customer/account/logout"> + <section name="account"/> + </action> + <!-- 6 - Action in both files has at least one identical Section --> <action name="customer/account/editPost"> <section name="account"/> + <section name="acc"/> + </action> + <!-- 7 - Action in both files has at least one identical Section and "*" --> + <action name="checkout/cart/delete"> + <section name="account"/> + <section name="acc"/> + </action> + <!-- 8 - Action in both files has Section and "*" --> + <action name="customer/account/createPost"> + <section name="account"/> + </action> + <!-- 9 - Action in both files has "*" and "*" --> + <action name="catalog/product_compare/add"> + <section name="*"/> + </action> + <!-- 10 - Action in both files has Section and "empty_section" --> + <action name="catalog/product_compare/remove"> + <section name="account"/> + <section name="acc"/> + </action> + <!-- 11 - Action in both files has "empty_section" and "empty_section" --> + <action name="catalog/product_compare/clear"/> + <!-- 12 - Action in both files has "*" and "empty_section" --> + <action name="checkout/cart/add"> + <section name="*"/> </action> </config> diff --git a/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections2.xml b/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections2.xml new file mode 100644 index 0000000000000..c3c2b29b358bd --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/CustomerData/_files/sections2.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> + <!-- Actions 5-12 are specified in files sections.xml and sections2.xml for merging --> + <!-- 5 - Action in both files has unique Section --> + <action name="customer/account/logout"> + <section name="cart"/> + </action> + <!-- 6 - Action in both files has at least one identical Section --> + <action name="customer/account/editPost"> + <section name="cart"/> + <section name="account"/> + </action> + <!-- 7 - Action in both files has at least one identical Section and "*" --> + <action name="checkout/cart/delete"> + <section name="cart"/> + <section name="*"/> + <section name="account"/> + </action> + <!-- 8 - Action in both files has Section and "*" --> + <action name="customer/account/createPost"> + <section name="*"/> + </action> + <!-- 9 - Action in both files has "*" and "*" --> + <action name="catalog/product_compare/add"> + <section name="*"/> + </action> + <!-- 10 - Action in both files has Section and "empty_section" --> + <action name="catalog/product_compare/remove"/> + <!-- 11 - Action in both files has "empty_section" and "empty_section" --> + <action name="catalog/product_compare/clear"/> + <!-- 12 - Action in both files has "*" and "empty_section" --> + <action name="checkout/cart/add"/> +</config> diff --git a/app/code/Magento/Customer/etc/frontend/sections.xml b/app/code/Magento/Customer/etc/frontend/sections.xml index 7938f28590ca8..e6a45dfdeaa49 100644 --- a/app/code/Magento/Customer/etc/frontend/sections.xml +++ b/app/code/Magento/Customer/etc/frontend/sections.xml @@ -7,10 +7,18 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> - <action name="customer/account/logout"/> - <action name="customer/account/loginPost"/> - <action name="customer/account/createPost"/> - <action name="customer/account/editPost"/> + <action name="customer/account/logout"> + <section name="*"/> + </action> + <action name="customer/account/loginPost"> + <section name="*"/> + </action> + <action name="customer/account/createPost"> + <section name="*"/> + </action> + <action name="customer/account/editPost"> + <section name="*"/> + </action> <action name="customer/ajax/login"> <section name="checkout-data"/> <section name="cart"/> diff --git a/app/code/Magento/Directory/etc/frontend/sections.xml b/app/code/Magento/Directory/etc/frontend/sections.xml index a2bc5696abf08..48d63ec82d95b 100644 --- a/app/code/Magento/Directory/etc/frontend/sections.xml +++ b/app/code/Magento/Directory/etc/frontend/sections.xml @@ -7,5 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> - <action name="directory/currency/switch"/> + <action name="directory/currency/switch"> + <section name="*"/> + </action> </config> diff --git a/app/code/Magento/Store/etc/frontend/sections.xml b/app/code/Magento/Store/etc/frontend/sections.xml index b7dbfe405263b..85f3627e05c95 100644 --- a/app/code/Magento/Store/etc/frontend/sections.xml +++ b/app/code/Magento/Store/etc/frontend/sections.xml @@ -7,6 +7,10 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> - <action name="stores/store/switch"/> - <action name="stores/store/switchrequest"/> + <action name="stores/store/switch"> + <section name="*"/> + </action> + <action name="stores/store/switchrequest"> + <section name="*"/> + </action> </config> From ac143c6d84dc7c7ffbf11c39d17940e946764f95 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 13 Feb 2020 15:55:13 -0600 Subject: [PATCH 36/43] MQE-2003: Bump MFTF version in Magento MFTF2.6.2 --- composer.json | 2 +- composer.lock | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index 8d38f1e0a151e..9c42a05a457c5 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,7 @@ "friendsofphp/php-cs-fixer": "~2.14.0", "lusitanian/oauth": "~0.8.10", "magento/magento-coding-standard": "*", - "magento/magento2-functional-testing-framework": "2.6.1", + "magento/magento2-functional-testing-framework": "2.6.2", "pdepend/pdepend": "2.5.2", "phpcompatibility/php-compatibility": "^9.3", "phpmd/phpmd": "@stable", diff --git a/composer.lock b/composer.lock index 347a50bdf68e0..6ac7f36cd2e32 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3b292997ff7767b89b6e08b0c550db7d", + "content-hash": "f06887dfc3e06489a251fbb5c18d30ca", "packages": [ { "name": "braintree/braintree_php", @@ -1850,6 +1850,11 @@ "MIT" ], "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, { "name": "Marijn Huizendveld", "email": "marijn.huizendveld@gmail.com" @@ -1857,11 +1862,6 @@ { "name": "Thibaud Fabre", "email": "thibaud@aztech.io" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" } ], "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", @@ -7381,16 +7381,16 @@ }, { "name": "magento/magento2-functional-testing-framework", - "version": "2.6.1", + "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/magento/magento2-functional-testing-framework.git", - "reference": "b00f5e195e1ed7f6335bce3052be9a0291f4d0db" + "reference": "8b332582751a830b3a6eafe1b09ac3b403e9a20e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/b00f5e195e1ed7f6335bce3052be9a0291f4d0db", - "reference": "b00f5e195e1ed7f6335bce3052be9a0291f4d0db", + "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/8b332582751a830b3a6eafe1b09ac3b403e9a20e", + "reference": "8b332582751a830b3a6eafe1b09ac3b403e9a20e", "shasum": "" }, "require": { @@ -7462,7 +7462,7 @@ "magento", "testing" ], - "time": "2020-02-11T22:23:54+00:00" + "time": "2020-02-13T21:29:32+00:00" }, { "name": "mikey179/vfsstream", From f8a929e50c75873d82f07c973faf177f612ddad8 Mon Sep 17 00:00:00 2001 From: "ivan.pletnyov" <ivan.pletnyov@transoftgroup.com> Date: Mon, 17 Feb 2020 13:13:38 +0200 Subject: [PATCH 37/43] MC-31524: Create/update customer address via customer repository --- .../Model/Address/CreateAddressTest.php | 44 ++++--- .../Model/Address/DeleteAddressTest.php | 6 +- .../Model/Address/UpdateAddressTest.php | 12 +- .../CustomerRepository/CreateAddressTest.php | 69 +++++++++++ .../CustomerRepository/DeleteAddressTest.php | 42 +++++++ .../CustomerRepository/UpdateAddressTest.php | 107 ++++++++++++++++++ 6 files changed, 247 insertions(+), 33 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/CreateAddressTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/DeleteAddressTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/UpdateAddressTest.php diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php index ae65c32fe3f43..c6e1a9bbf8ac5 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php @@ -38,7 +38,7 @@ class CreateAddressTest extends TestCase AddressInterface::COUNTRY_ID => 'US', 'custom_region_name' => 'Alabama', AddressInterface::CITY => 'CityM', - AddressInterface::STREET => 'Green str, 67', + AddressInterface::STREET => ['Green str, 67'], AddressInterface::LASTNAME => 'Smith', AddressInterface::FIRSTNAME => 'John', ]; @@ -46,42 +46,42 @@ class CreateAddressTest extends TestCase /** * @var ObjectManager */ - private $objectManager; + protected $objectManager; /** - * @var GetRegionIdByName + * @var AddressInterfaceFactory */ - private $getRegionIdByName; + protected $addressFactory; /** - * @var AddressInterfaceFactory + * @var CustomerRegistry */ - private $addressFactory; + protected $customerRegistry; /** - * @var AddressRegistry + * @var AddressRepositoryInterface */ - private $addressRegistry; + protected $addressRepository; /** - * @var Address + * @var GetRegionIdByName */ - private $addressResource; + protected $getRegionIdByName; /** - * @var CustomerRegistry + * @var CustomerRepositoryInterface */ - private $customerRegistry; + protected $customerRepository; /** - * @var AddressRepositoryInterface + * @var AddressRegistry */ - private $addressRepository; + private $addressRegistry; /** - * @var CustomerRepositoryInterface + * @var Address */ - private $customerRepository; + private $addressResource; /** * @var int[] @@ -94,13 +94,13 @@ class CreateAddressTest extends TestCase protected function setUp() { $this->objectManager = Bootstrap::getObjectManager(); - $this->getRegionIdByName = $this->objectManager->get(GetRegionIdByName::class); $this->addressFactory = $this->objectManager->get(AddressInterfaceFactory::class); - $this->addressRegistry = $this->objectManager->get(AddressRegistry::class); - $this->addressResource = $this->objectManager->get(Address::class); $this->customerRegistry = $this->objectManager->get(CustomerRegistry::class); $this->addressRepository = $this->objectManager->get(AddressRepositoryInterface::class); + $this->getRegionIdByName = $this->objectManager->get(GetRegionIdByName::class); $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class); + $this->addressRegistry = $this->objectManager->get(AddressRegistry::class); + $this->addressResource = $this->objectManager->get(Address::class); parent::setUp(); } @@ -310,10 +310,6 @@ public function createWrongAddressesDataProvider(): array array_replace(self::STATIC_CUSTOMER_ADDRESS_DATA, [AddressInterface::LASTNAME => '']), InputException::requiredField('lastname'), ], - 'required_field_empty_street_as_string' => [ - array_replace(self::STATIC_CUSTOMER_ADDRESS_DATA, [AddressInterface::STREET => '']), - InputException::requiredField('street'), - ], 'required_field_empty_street_as_array' => [ array_replace(self::STATIC_CUSTOMER_ADDRESS_DATA, [AddressInterface::STREET => []]), InputException::requiredField('street'), @@ -339,7 +335,7 @@ public function createWrongAddressesDataProvider(): array * @param bool $isDefaultBilling * @return AddressInterface */ - private function createAddress( + protected function createAddress( int $customerId, array $addressData, bool $isDefaultShipping = false, diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/DeleteAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/DeleteAddressTest.php index fe5437e294fc6..b303e8b0d1ca7 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/DeleteAddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/DeleteAddressTest.php @@ -30,17 +30,17 @@ class DeleteAddressTest extends TestCase /** * @var CustomerRegistry */ - private $customerRegistry; + protected $customerRegistry; /** * @var AddressRepositoryInterface */ - private $addressRepository; + protected $addressRepository; /** * @var CustomerRepositoryInterface */ - private $customerRepository; + protected $customerRepository; /** * @inheritdoc diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/UpdateAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/UpdateAddressTest.php index 8867f269cdf37..902c9ae2407a7 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/UpdateAddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/UpdateAddressTest.php @@ -33,32 +33,32 @@ class UpdateAddressTest extends TestCase /** * @var AddressRegistry */ - private $addressRegistry; + protected $addressRegistry; /** * @var Address */ - private $addressResource; + protected $addressResource; /** * @var CustomerRegistry */ - private $customerRegistry; + protected $customerRegistry; /** * @var AddressRepositoryInterface */ - private $addressRepository; + protected $addressRepository; /** * @var CustomerRepositoryInterface */ - private $customerRepository; + protected $customerRepository; /** * @var int[] */ - private $processedAddressesIds = []; + protected $processedAddressesIds = []; /** * @inheritdoc diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/CreateAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/CreateAddressTest.php new file mode 100644 index 0000000000000..a866910332b0c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/CreateAddressTest.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Model\ResourceModel\CustomerRepository; + +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Model\Address\CreateAddressTest as CreateAddressViaAddressRepositoryTest; +use Magento\Framework\Api\DataObjectHelper; + +/** + * Test cases related to create customer address using customer repository. + * + * @magentoDbIsolation enabled + */ +class CreateAddressTest extends CreateAddressViaAddressRepositoryTest +{ + /** + * @var DataObjectHelper + */ + private $dataObjectHelper; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + $this->dataObjectHelper = $this->objectManager->get(DataObjectHelper::class); + } + + /** + * Create customer address with provided address data. + * + * @param int $customerId + * @param array $addressData + * @param bool $isDefaultShipping + * @param bool $isDefaultBilling + * @return AddressInterface + */ + protected function createAddress( + int $customerId, + array $addressData, + bool $isDefaultShipping = false, + bool $isDefaultBilling = false + ): AddressInterface { + if (isset($addressData['custom_region_name'])) { + $addressData[AddressInterface::REGION_ID] = $this->getRegionIdByName->execute( + $addressData['custom_region_name'], + $addressData[AddressInterface::COUNTRY_ID] + ); + unset($addressData['custom_region_name']); + } + $address = $this->addressFactory->create(); + $this->dataObjectHelper->populateWithArray($address, $addressData, AddressInterface::class); + $address->setIsDefaultShipping($isDefaultShipping); + $address->setIsDefaultBilling($isDefaultBilling); + $customer = $this->customerRepository->getById($customerId); + $customer->setAddresses([$address]); + $this->customerRepository->save($customer); + $addressId = (int)$address->getId(); + $this->customerRegistry->remove($customerId); + + return $this->addressRepository->getById($addressId); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/DeleteAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/DeleteAddressTest.php new file mode 100644 index 0000000000000..dd3adebc92cc2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/DeleteAddressTest.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Model\ResourceModel\CustomerRepository; + +use Magento\Customer\Model\Address\DeleteAddressTest as DeleteAddressViaAddressRepositoryTest; +use Magento\Framework\Exception\NoSuchEntityException; + +/** + * Test cases related to delete customer address using customer repository. + * + * @magentoDbIsolation enabled + */ +class DeleteAddressTest extends DeleteAddressViaAddressRepositoryTest +{ + /** + * Assert that address deleted successfully. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + * + * @return void + */ + public function testDeleteDefaultAddress(): void + { + $customer = $this->customerRepository->get('customer@example.com'); + $this->assertEquals(1, $customer->getDefaultShipping()); + $this->assertEquals(1, $customer->getDefaultBilling()); + $customer->setAddresses([]); + $this->customerRepository->save($customer); + $this->customerRegistry->remove($customer->getId()); + $customer = $this->customerRepository->get('customer@example.com'); + $this->assertNull($customer->getDefaultShipping()); + $this->assertNull($customer->getDefaultBilling()); + $this->expectExceptionObject(new NoSuchEntityException(__('No such entity with addressId = 1'))); + $this->addressRepository->getById(1); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/UpdateAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/UpdateAddressTest.php new file mode 100644 index 0000000000000..789c61bdbaf5c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepository/UpdateAddressTest.php @@ -0,0 +1,107 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Model\ResourceModel\CustomerRepository; + +use Magento\Customer\Model\Address\UpdateAddressTest as UpdateAddressViaAddressRepositoryTest; + +/** + * Test cases related to update customer address using customer repository. + * + * @magentoDbIsolation enabled + */ +class UpdateAddressTest extends UpdateAddressViaAddressRepositoryTest +{ + /** + * Assert that default addresses properly updated for customer. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + * + * @dataProvider updateAddressIsDefaultDataProvider + * + * @param bool $isShippingDefault + * @param bool $isBillingDefault + * @param int|null $expectedShipping + * @param int|null $expectedBilling + * @return void + */ + public function testUpdateAddressIsDefault( + bool $isShippingDefault, + bool $isBillingDefault, + ?int $expectedShipping, + ?int $expectedBilling + ): void { + $customer = $this->customerRepository->get('customer@example.com'); + $this->assertEquals(1, $customer->getDefaultShipping()); + $this->assertEquals(1, $customer->getDefaultBilling()); + $this->processedAddressesIds[] = 1; + $address = $this->addressRepository->getById(1); + $address->setIsDefaultShipping($isShippingDefault); + $address->setIsDefaultBilling($isBillingDefault); + $customer->setAddresses([$address]); + $this->customerRepository->save($customer); + $this->customerRegistry->remove(1); + $customer = $this->customerRepository->get('customer@example.com'); + $this->assertEquals($customer->getDefaultShipping(), $expectedShipping); + $this->assertEquals($customer->getDefaultBilling(), $expectedBilling); + } + + /** + * Assert that address updated successfully. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + * + * @dataProvider updateAddressesDataProvider + * + * @param array $updateData + * @param array $expectedData + * @return void + */ + public function testUpdateAddress(array $updateData, array $expectedData): void + { + $this->processedAddressesIds[] = 1; + $address = $this->addressRepository->getById(1); + foreach ($updateData as $setFieldName => $setValue) { + $address->setData($setFieldName, $setValue); + } + $customer = $this->customerRepository->get('customer@example.com'); + $customer->setAddresses([$address]); + $this->customerRepository->save($customer); + $updatedAddressData = $this->addressRepository->getById((int)$address->getId())->__toArray(); + foreach ($expectedData as $getFieldName => $getValue) { + $this->assertTrue(isset($updatedAddressData[$getFieldName]), "Field $getFieldName wasn't found."); + $this->assertEquals($getValue, $updatedAddressData[$getFieldName]); + } + } + + /** + * Assert that error message has thrown during process address update. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + * + * @dataProvider updateWrongAddressesDataProvider + * + * @param array $updateData + * @param \Exception $expectException + * @return void + */ + public function testExceptionThrownDuringUpdateAddress(array $updateData, \Exception $expectException): void + { + $this->processedAddressesIds[] = 1; + $address = $this->addressRepository->getById(1); + $customer = $this->customerRepository->get('customer@example.com'); + foreach ($updateData as $setFieldName => $setValue) { + $address->setData($setFieldName, $setValue); + } + $customer->setAddresses([$address]); + $this->expectExceptionObject($expectException); + $this->customerRepository->save($customer); + } +} From 90436f68b524be4d1d467c2032604fe877f1de63 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Tue, 18 Feb 2020 10:31:18 +0200 Subject: [PATCH 38/43] MC-31526: Indexer price calculation for fixed/dynamic bundle product with different type prices --- .../Bundle/Model/Product/PriceTest.php | 525 +++++++++++++++++- ...namic_bundle_product_with_catalog_rule.php | 117 ++++ ...dle_product_with_catalog_rule_rollback.php | 57 ++ ...amic_bundle_product_with_special_price.php | 70 +++ ...le_product_with_special_price_rollback.php | 23 + ...dynamic_bundle_product_with_tier_price.php | 94 ++++ ...undle_product_with_tier_price_rollback.php | 23 + ...namic_bundle_product_without_discounts.php | 69 +++ ...dle_product_without_discounts_rollback.php | 23 + ...ixed_bundle_product_with_special_price.php | 77 +++ ...le_product_with_special_price_rollback.php | 23 + .../fixed_bundle_product_with_tier_price.php | 101 ++++ ...undle_product_with_tier_price_rollback.php | 23 + ...fixed_bundle_product_without_discounts.php | 76 +++ ...dle_product_without_discounts_rollback.php | 23 + ...category_with_different_price_products.php | 24 +- .../_files/catalog_rule_for_category_999.php | 59 ++ ...catalog_rule_for_category_999_rollback.php | 28 + 18 files changed, 1400 insertions(+), 35 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php index 4a5757aae3134..b9ffbcf4549ea 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php @@ -3,68 +3,106 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Bundle\Model\Product; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\Data\TierPriceInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Model\Group; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Catalog\Model\GetCategoryByName; +use Magento\TestFramework\Catalog\Model\Product\Price\GetPriceIndexDataByProductId; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + /** * Class to test bundle prices + * + * @magentoDbIsolation disabled + * @magentoAppIsolation enabled + * @magentoAppArea frontend + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class PriceTest extends \PHPUnit\Framework\TestCase +class PriceTest extends TestCase { + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var GetPriceIndexDataByProductId */ + private $getPriceIndexDataByProductId; + + /** @var WebsiteRepositoryInterface */ + private $websiteRepository; + + /** @var Price */ + private $priceModel; + + /** @var SerializerInterface */ + private $json; + + /** @var GetCategoryByName */ + private $getCategoryByName; + /** - * @var \Magento\Bundle\Model\Product\Price + * @inheritdoc */ - protected $_model; - protected function setUp() { - $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Bundle\Model\Product\Price::class - ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->priceModel = $this->objectManager->get(Price::class); + $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->getPriceIndexDataByProductId = $this->objectManager->get(GetPriceIndexDataByProductId::class); + $this->json = $this->objectManager->get(SerializerInterface::class); + $this->getCategoryByName = $this->objectManager->get(GetCategoryByName::class); } /** * @magentoDataFixture Magento/Bundle/_files/product_with_tier_pricing.php + * + * @return void */ - public function testGetTierPrice() + public function testGetTierPrice(): void { - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ - $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); - $product = $productRepository->get('bundle-product'); - // fixture - + $product = $this->productRepository->get('bundle-product'); // Note that this is really not the "tier price" but the "tier discount percentage" // so it is expected to be increasing instead of decreasing - $this->assertEquals(8.0, $this->_model->getTierPrice(2, $product)); - $this->assertEquals(20.0, $this->_model->getTierPrice(3, $product)); - $this->assertEquals(20.0, $this->_model->getTierPrice(4, $product)); - $this->assertEquals(30.0, $this->_model->getTierPrice(5, $product)); + $this->assertEquals(8.0, $this->priceModel->getTierPrice(2, $product)); + $this->assertEquals(20.0, $this->priceModel->getTierPrice(3, $product)); + $this->assertEquals(20.0, $this->priceModel->getTierPrice(4, $product)); + $this->assertEquals(30.0, $this->priceModel->getTierPrice(5, $product)); } /** * Test calculation final price for bundle product with tire price in simple product + * @magentoDataFixture Magento/Bundle/_files/product_with_simple_tier_pricing.php + * @dataProvider getSelectionFinalTotalPriceWithSimpleTierPriceDataProvider * * @param float $bundleQty * @param float $selectionQty * @param float $finalPrice - * @magentoDataFixture Magento/Bundle/_files/product_with_simple_tier_pricing.php - * @dataProvider getSelectionFinalTotalPriceWithSimpleTierPriceDataProvider + * @return void */ public function testGetSelectionFinalTotalPriceWithSimpleTierPrice( float $bundleQty, float $selectionQty, float $finalPrice - ) { - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ - $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); - $bundleProduct = $productRepository->get('bundle-product'); - $simpleProduct = $productRepository->get('simple'); - $simpleProduct->setCustomerGroupId(\Magento\Customer\Model\Group::CUST_GROUP_ALL); + ): void { + $bundleProduct = $this->productRepository->get('bundle-product'); + $simpleProduct = $this->productRepository->get('simple'); + $simpleProduct->setCustomerGroupId(Group::CUST_GROUP_ALL); $this->assertEquals( $finalPrice, - $this->_model->getSelectionFinalTotalPrice( + $this->priceModel->getSelectionFinalTotalPrice( $bundleProduct, $simpleProduct, $bundleQty, @@ -86,4 +124,435 @@ public function getSelectionFinalTotalPriceWithSimpleTierPriceDataProvider(): ar [5, 1, 5], ]; } + + /** + * Fixed Bundle Product with catalog price rule + * @magentoDataFixture Magento/Bundle/_files/fixed_bundle_product_without_discounts.php + * @magentoDataFixture Magento/CatalogRule/_files/rule_apply_as_percentage_of_original_not_logged_user.php + * + * @return void + */ + public function testFixedBundleProductPriceWithCatalogRule(): void + { + $this->checkBundlePrices( + 'fixed_bundle_product_without_discounts', + ['price' => 50, 'final_price' => 45, 'min_price' => 45, 'max_price' => 75, 'tier_price' => null], + ['simple1' => 55, 'simple2' => 56.25, 'simple3' => 70] + ); + } + + /** + * Fixed Bundle Product without discounts + * @magentoDataFixture Magento/Bundle/_files/fixed_bundle_product_without_discounts.php + * + * @return void + */ + public function testFixedBundleProductPriceWithoutDiscounts(): void + { + $this->checkBundlePrices( + 'fixed_bundle_product_without_discounts', + ['price' => 50, 'final_price' => 50, 'min_price' => 60, 'max_price' => 75, 'tier_price' => null], + ['simple1' => 60, 'simple2' => 62.5, 'simple3' => 75] + ); + } + + /** + * Fixed Bundle Product with special price + * @magentoDataFixture Magento/Bundle/_files/fixed_bundle_product_with_special_price.php + * + * @return void + */ + public function testFixedBundleProductPriceWithSpecialPrice(): void + { + $this->checkBundlePrices( + 'fixed_bundle_product_with_special_price', + ['price' => 50, 'final_price' => 40, 'min_price' => 48, 'max_price' => 60, 'tier_price' => null], + ['simple1' => 48, 'simple2' => 50, 'simple3' => 60] + ); + } + + /** + * Fixed Bundle Product with tier price + * @magentoDataFixture Magento/Bundle/_files/fixed_bundle_product_with_tier_price.php + * + * @return void + */ + public function testFixedBundleProductPriceWithTierPrice(): void + { + $this->checkBundlePrices( + 'fixed_bundle_product_with_tier_price', + ['price' => 50, 'final_price' => 50, 'min_price' => 60, 'max_price' => 75, 'tier_price' => 60], + ['simple1' => 45, 'simple2' => 46.88, 'simple3' => 56.25] + ); + } + + /** + * Dynamic Bundle Product without discount + options without discounts + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php + * + * @return void + */ + public function testDynamicBundleProductWithoutDiscountAndOptionsWithoutDiscounts(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_without_discounts', + ['price' => 0, 'final_price' => 0, 'min_price' => 10, 'max_price' => 20, 'tier_price' => null], + ['simple1000' => 10, 'simple1001' => 20] + ); + } + + /** + * Dynamic Bundle Product without discount + options with special price + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php + * + * @return void + */ + public function testDynamicBundleProductWithoutDiscountsAndOptionsWithSpecialPrices(): void + { + $this->updateProducts($this->specialPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_without_discounts', + ['price' => 0, 'final_price' => 0, 'min_price' => 8, 'max_price' => 15, 'tier_price' => null], + ['simple1000' => 8, 'simple1001' => 15] + ); + } + + /** + * Dynamic Bundle Product without discount + options with tier prices + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php + * + * @return void + */ + public function testDynamicBundleProductWithoutDiscountsAndOptionsWithTierPrices(): void + { + $this->updateProducts($this->tierPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_without_discounts', + ['price' => 0, 'final_price' => 0, 'min_price' => 8, 'max_price' => 17, 'tier_price' => null], + ['simple1000' => 8, 'simple1001' => 17] + ); + } + + /** + * Dynamic Bundle Product without discounts + options with catalog rule + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php + * @magentoDataFixture Magento/CatalogRule/_files/catalog_rule_for_category_999.php + * + * @return void + */ + public function testDynamicBundleProductWithoutDiscountsAndOptionsWithCatalogPriceRule(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_without_discounts', + ['price' => 0, 'final_price' => 0, 'min_price' => 7.5, 'max_price' => 15, 'tier_price' => null], + ['simple1000' => 7.5, 'simple1001' => 15] + ); + } + + /** + * Dynamic Bundle Product with tier price + options without discounts + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php + * + * @return void + */ + public function testDynamicBundleProductWithTierPriceAndOptionsWithoutDiscounts(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_with_tier_price', + ['price' => 0,'final_price' => 0, 'min_price' => 10, 'max_price' => 20, 'tier_price' => 10], + ['simple1000' => 7.5, 'simple1001' => 15] + ); + } + + /** + * Dynamic Bundle Product with tier price + options with special prices + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php + * + * @return void + */ + public function testDynamicBundleProductWithTierPriceAndOptionsWithSpecialPrices(): void + { + $this->updateProducts($this->specialPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_with_tier_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 8, 'max_price' => 15, 'tier_price' => 8], + ['simple1000' => 6, 'simple1001' => 11.25] + ); + } + + /** + * Dynamic Bundle Product with tier price + options with tier price + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php + * + * @return void + */ + public function testDynamicBundleProductWithTierPriceAndOptionsWithTierPrices(): void + { + $this->updateProducts($this->tierPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_with_tier_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 8, 'max_price' => 17, 'tier_price' => 8], + ['simple1000' => 6, 'simple1001' => 12.75] + ); + } + + /** + * Dynamic Bundle Product with tier price + options with catalog rule + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php + * @magentoDataFixture Magento/CatalogRule/_files/catalog_rule_for_category_999.php + * + * @return void + */ + public function testDynamicBundleProductWithTierPriceAndOptionsWithCatalogPriceRule(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_with_tier_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 7.5, 'max_price' => 15, 'tier_price' => 7.5], + ['simple1000' => 5.63, 'simple1001' => 11.25] + ); + } + + /** + * Dynamic Bundle Product with special price + options without discounts + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php + * + * @return void + */ + public function testDynamicBundleProductWithSpecialPriceAndOptionsWithoutDiscounts(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_with_special_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 7.5, 'max_price' => 15, 'tier_price' => null], + ['simple1000' => 7.5, 'simple1001' => 15] + ); + } + + /** + * Dynamic Bundle Product with special price + options with special prices + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php + * + * @return void + */ + public function testDynamicBundleProductWithSpecialPriceAndOptionsWithSpecialPrices(): void + { + $this->updateProducts($this->specialPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_with_special_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 6, 'max_price' => 11.25, 'tier_price' => null], + ['simple1000' => 6, 'simple1001' => 11.25] + ); + } + + /** + * Dynamic Bundle Product with special price + options with tier prices + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php + * + * @return void + */ + public function testDynamicBundleProductWithSpecialPriceAndOptionsWithTierPrices(): void + { + $this->updateProducts($this->tierPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_with_special_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 6, 'max_price' => 12.75, 'tier_price' => null], + ['simple1000' => 6, 'simple1001' => 12.75] + ); + } + + /** + * Dynamic Bundle Product with special price + options with catalog price rule + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php + * @magentoDataFixture Magento/CatalogRule/_files/catalog_rule_for_category_999.php + * + * @return void + */ + public function testDynamicBundleProductWithSpecialPriceAndOptionsWithCatalogPriceRule(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_with_special_price', + ['price' => 0, 'final_price' => 0, 'min_price' => 5.625, 'max_price' => 11.25, 'tier_price' => null], + ['simple1000' => 5.63, 'simple1001' => 11.25] + ); + } + + /** + * Dynamic Bundle Product with catalog price rule + options without discounts + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php + * + * @return void + */ + public function testDynamicBundleProductWithCatalogPriceRuleAndOptionsWithoutDiscounts(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_with_catalog_rule', + ['price' => 0, 'final_price' => 0, 'min_price' => 10, 'max_price' => 20, 'tier_price' => null], + ['simple1000' => 10, 'simple1001' => 20] + ); + } + + /** + * Dynamic Bundle Product with catalog price rule + options with catalog price rule + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php + * @magentoDataFixture Magento/CatalogRule/_files/catalog_rule_for_category_999.php + * + * @return void + */ + public function testDynamicBundleProductWithCatalogPriceRuleAndOptionsWithCatalogPriceRule(): void + { + $this->checkBundlePrices( + 'dynamic_bundle_product_with_catalog_rule', + ['price' => 0, 'final_price' => 0, 'min_price' => 7.5, 'max_price' => 15, 'tier_price' => null], + ['simple1000' => 7.5, 'simple1001' => 15] + ); + } + + /** + * Dynamic Bundle Product with catalog price rule + options with special prices + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php + * + * @return void + */ + public function testDynamicBundleProductWithCatalogPriceRuleAndOptionsWithSpecialPrices(): void + { + $this->updateProducts($this->specialPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_with_catalog_rule', + ['price' => 0, 'final_price' => 0, 'min_price' => 8, 'max_price' => 15, 'tier_price' => null], + ['simple1000' => 8, 'simple1001' => 15] + ); + } + + /** + * Dynamic Bundle Product with catalog price rule + options with tier price + * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php + * + * @return void + */ + public function testDynamicBundleProductWithCatalogPriceRuleAndOptionsWithTierPrice(): void + { + $this->updateProducts($this->tierPricesForOptionsData()); + $this->checkBundlePrices( + 'dynamic_bundle_product_with_catalog_rule', + ['price' => 0, 'final_price' => 0, 'min_price' => 8, 'max_price' => 17, 'tier_price' => null], + ['simple1000' => 8, 'simple1001' => 17] + ); + } + + /** + * Check bundle prices from index table and final bundle option price. + * + * @param string $sku + * @param array $indexPrices + * @param array $expectedPrices + * @return void + */ + private function checkBundlePrices(string $sku, array $indexPrices, array $expectedPrices): void + { + $product = $this->productRepository->get($sku); + $this->assertIndexTableData((int)$product->getId(), $indexPrices); + $this->assertPriceWithChosenOption($product, $expectedPrices); + } + + /** + * Asserts price data in index table. + * + * @param int $productId + * @param array $expectedPrices + * @return void + */ + private function assertIndexTableData(int $productId, array $expectedPrices): void + { + $data = $this->getPriceIndexDataByProductId->execute( + $productId, + Group::NOT_LOGGED_IN_ID, + (int)$this->websiteRepository->get('base')->getId() + ); + $data = reset($data); + foreach ($expectedPrices as $column => $price) { + $this->assertEquals($price, $data[$column]); + } + } + + /** + * Assert bundle final price with chosen option. + * + * @param ProductInterface $bundle + * @param array $expectedPrices + * @return void + */ + private function assertPriceWithChosenOption(ProductInterface $bundle, array $expectedPrices): void + { + $option = $bundle->getExtensionAttributes()->getBundleProductOptions()[0] ?? null; + $this->assertNotNull($option); + foreach ($option->getProductLinks() as $productLink) { + $bundle->addCustomOption('bundle_selection_ids', $this->json->serialize([$productLink->getId()])); + $bundle->addCustomOption('selection_qty_' . $productLink->getId(), 1); + $this->assertEquals( + round($expectedPrices[$productLink->getSku()], 2), + round($this->priceModel->getFinalPrice(1, $bundle), 2) + ); + } + } + + /** + * Update products. + * + * @param array $products + * @return void + */ + private function updateProducts(array $products): void + { + foreach ($products as $sku => $updateData) { + $product = $this->productRepository->get($sku); + $product->addData($updateData); + $this->productRepository->save($product); + } + } + + /** + * @return array + */ + private function specialPricesForOptionsData(): array + { + return [ + 'simple1000' => [ + 'special_price' => 8, + ], + 'simple1001' => [ + 'special_price' => 15, + ], + ]; + } + + /** + * @return array + */ + private function tierPricesForOptionsData(): array + { + return [ + 'simple1000' => [ + 'tier_price' => [ + [ + 'website_id' => 0, + 'cust_group' => Group::CUST_GROUP_ALL, + 'price_qty' => 1, + 'value_type' => TierPriceInterface::PRICE_TYPE_FIXED, + 'price' => 8, + ], + ], + ], + 'simple1001' => [ + 'tier_price' => [ + [ + 'website_id' => 0, + 'cust_group' => Group::CUST_GROUP_ALL, + 'price_qty' => 1, + 'value_type' => TierPriceInterface::PRICE_TYPE_DISCOUNT, + 'website_price' => 20, + 'percentage_value' => 15, + ], + ], + ], + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php new file mode 100644 index 0000000000000..44d995a4b8baf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule.php @@ -0,0 +1,117 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface; +use Magento\CatalogRule\Api\Data\RuleInterface; +use Magento\CatalogRule\Api\Data\RuleInterfaceFactory; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\Rule\Condition\Combine; +use Magento\CatalogRule\Model\Rule\Condition\Product; +use Magento\Customer\Model\Group; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); +/** @var RuleInterfaceFactory $catalogRuleFactory */ +$catalogRuleFactory = $objectManager->get(RuleInterfaceFactory::class); +/** @var CatalogRuleRepositoryInterface $catalogRuleRepository */ +$catalogRuleRepository = $objectManager->get(CatalogRuleRepositoryInterface::class); +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); +$defaultWebsiteId = $storeManager->getWebsite('base')->getId(); + +$category = $categoryFactory->create(); +$category->isObjectNew(true); +$category->setName('Category with bundle product and rule') + ->setParentId($categoryHelper->getId()) + ->setIsActive(true) + ->setPosition(1); +$category = $categoryRepository->save($category); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('dynamic_bundle_product_with_catalog_rule') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setSkuType(0) + ->setPriceView(0) + ->setPriceType(Price::PRICE_TYPE_DYNAMIC) + ->setPrice(null) + ->setWeightType(0) + ->setCategoryIds([$category->getId()]) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'select', + 'required' => 1, + ], +]; +$bundleSelectionsData = [ + [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + ] +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, $bundleSelectionsData); +$productRepository->save($bundleProduct); + +$ruleData = [ + RuleInterface::NAME => 'Rule for bundle product', + RuleInterface::IS_ACTIVE => 1, + 'website_ids' => [$defaultWebsiteId], + 'customer_group_ids' => Group::NOT_LOGGED_IN_ID, + RuleInterface::DISCOUNT_AMOUNT => 50, + RuleInterface::SIMPLE_ACTION => 'by_percent', + 'conditions' => [ + '1' => [ + 'type' => Combine::class, + 'aggregator' => 'all', + 'value' => '1', + ], + '1--1' => [ + 'type' => Product::class, + 'attribute' => 'category_ids', + 'operator' => '==', + 'value' => $category->getId(), + ], + ], +]; +$catalogRule = $catalogRuleFactory->create(); +$catalogRule->loadPost($ruleData); +$catalogRuleRepository->save($catalogRule); +$indexBuilder->reindexFull(); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule_rollback.php new file mode 100644 index 0000000000000..cf3fd4a9e14ff --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_catalog_rule_rollback.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\TestFramework\Catalog\Model\GetCategoryByName; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products_rollback.php'; + +/** @var GetCategoryByName $getCategoryByName */ +$getCategoryByName = $objectManager->create(GetCategoryByName::class); +/** @var CollectionFactory $ruleCollectionFactory */ +$ruleCollectionFactory = $objectManager->get(CollectionFactory::class); +/** @var CatalogRuleRepositoryInterface $ruleRepository */ +$ruleRepository = $objectManager->get(CatalogRuleRepositoryInterface::class); +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('dynamic_bundle_product_with_catalog_rule', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //product already deleted. +} + +$category = $getCategoryByName->execute('Category with bundle product and rule'); + +try { + $categoryRepository->delete($category); +} catch (NoSuchEntityException $e) { + //category already deleted. +} + +$ruleCollection = $ruleCollectionFactory->create(); +$ruleCollection->addFieldToFilter('name', 'Rule for bundle product'); +$ruleCollection->setPageSize(1); +$catalogRule = $ruleCollection->getFirstItem(); + +try { + $ruleRepository->delete($catalogRule); +} catch (Exception $ex) { + //Nothing to remove +} + +$indexBuilder->reindexFull(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php new file mode 100644 index 0000000000000..e5fef4e581595 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); +$defaultWebsiteId = $storeManager->getWebsite('base')->getId(); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('dynamic_bundle_product_with_special_price') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setSkuType(0) + ->setPriceView(0) + ->setPriceType(Price::PRICE_TYPE_DYNAMIC) + ->setPrice(null) + ->setSpecialPrice(75) + ->setWeightType(0) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'select', + 'required' => 1, + ], +]; +$bundleSelectionsData = [ + [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + ] +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, $bundleSelectionsData); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price_rollback.php new file mode 100644 index 0000000000000..0ec7cc98131d4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_special_price_rollback.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Exception\NoSuchEntityException; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('dynamic_bundle_product_with_special_price', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //product already deleted. +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php new file mode 100644 index 0000000000000..b1cdfddd061bb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory; +use Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; +use Magento\Customer\Model\Group; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); +/** @var ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(ProductTierPriceInterfaceFactory::class); +/** @var $tierPriceExtensionAttributesFactory */ +$tierPriceExtensionAttributesFactory = $objectManager->get(ProductTierPriceExtensionFactory::class); +$defaultWebsiteId = $storeManager->getWebsite('base')->getId(); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('dynamic_bundle_product_with_tier_price') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setSkuType(0) + ->setPriceView(0) + ->setPriceType(Price::PRICE_TYPE_DYNAMIC) + ->setPrice(null) + ->setWeightType(0) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'select', + 'required' => 1, + ], +]; +$bundleSelectionsData = [ + [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + ] +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, $bundleSelectionsData); + +$tierPriceExtensionAttribute = $tierPriceExtensionAttributesFactory->create( + [ + 'data' => [ + 'website_id' => 0, + 'percentage_value' => 25, + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => Group::CUST_GROUP_ALL, + 'qty' => 1, + ] + ] +)->setExtensionAttributes($tierPriceExtensionAttribute); +$bundleProduct->setTierPrices($tierPrices); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price_rollback.php new file mode 100644 index 0000000000000..247e2400986d7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_with_tier_price_rollback.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Exception\NoSuchEntityException; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('dynamic_bundle_product_with_tier_price', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //product already deleted. +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php new file mode 100644 index 0000000000000..4b0b81f5d9f04 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); +$defaultWebsiteId = $storeManager->getWebsite('base')->getId(); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('dynamic_bundle_product_without_discounts') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setSkuType(0) + ->setPriceView(0) + ->setPriceType(Price::PRICE_TYPE_DYNAMIC) + ->setPrice(null) + ->setWeightType(0) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'select', + 'required' => 1, + ], +]; +$bundleSelectionsData = [ + [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 0, + 'selection_can_change_qty' => 1, + ], + ] +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, $bundleSelectionsData); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts_rollback.php new file mode 100644 index 0000000000000..cb785aee1ccd7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/dynamic_bundle_product_without_discounts_rollback.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Exception\NoSuchEntityException; + +require __DIR__ . '/../../../Magento/Catalog/_files/category_with_different_price_products_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('dynamic_bundle_product_without_discounts', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //product already deleted. +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price.php new file mode 100644 index 0000000000000..d7caba1dec4aa --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; + +require __DIR__ . '/multiple_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('fixed_bundle_product_with_special_price') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setPriceView(1) + ->setSkuType(1) + ->setWeightType(1) + ->setPriceType(Price::PRICE_TYPE_FIXED) + ->setPrice(50.0) + ->setSpecialPrice(80) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'radio', + 'required' => 1, + 'delete' => '', + ], +]; +$bundleSelectionsData = [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 10, + 'selection_price_type' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 25, + 'selection_price_type' => 1, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product3->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 25, + 'selection_price_type' => 0, + 'selection_can_change_qty' => 1, + ], +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, [$bundleSelectionsData]); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price_rollback.php new file mode 100644 index 0000000000000..2fd27a34a1f2a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_special_price_rollback.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Exception\NoSuchEntityException; + +require __DIR__ . '/multiple_products_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('fixed_bundle_product_with_special_price', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price.php new file mode 100644 index 0000000000000..64de77d87085d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price.php @@ -0,0 +1,101 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory; +use Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Customer\Model\Group; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; + +require __DIR__ . '/multiple_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); +/** @var ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(ProductTierPriceInterfaceFactory::class); +/** @var $tierPriceExtensionAttributesFactory */ +$tierPriceExtensionAttributesFactory = $objectManager->get(ProductTierPriceExtensionFactory::class); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('fixed_bundle_product_with_tier_price') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setPriceView(1) + ->setSkuType(1) + ->setWeightType(1) + ->setPriceType(Price::PRICE_TYPE_FIXED) + ->setPrice(50.0) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'radio', + 'required' => 1, + 'delete' => '', + ], +]; +$bundleSelectionsData = [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 10, + 'selection_price_type' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 25, + 'selection_price_type' => 1, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product3->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 25, + 'selection_price_type' => 0, + 'selection_can_change_qty' => 1, + ], +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, [$bundleSelectionsData]); + +$tierPriceExtensionAttribute = $tierPriceExtensionAttributesFactory->create( + [ + 'data' => [ + 'website_id' => 0, + 'percentage_value' => 25, + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => Group::CUST_GROUP_ALL, + 'qty' => 1, + ] + ] +)->setExtensionAttributes($tierPriceExtensionAttribute); +$bundleProduct->setTierPrices($tierPrices); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price_rollback.php new file mode 100644 index 0000000000000..0e3be5936876a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_with_tier_price_rollback.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Exception\NoSuchEntityException; + +require __DIR__ . '/multiple_products_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('fixed_bundle_product_with_tier_price', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts.php new file mode 100644 index 0000000000000..1b5d6b2eb60d2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; + +require __DIR__ . '/multiple_products.php'; + +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('fixed_bundle_product_without_discounts') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setPriceView(1) + ->setSkuType(1) + ->setWeightType(1) + ->setPriceType(Price::PRICE_TYPE_FIXED) + ->setPrice(50.0) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'radio', + 'required' => 1, + 'delete' => '', + ], +]; +$bundleSelectionsData = [ + [ + 'sku' => $product->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 10, + 'selection_price_type' => 0, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product2->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 25, + 'selection_price_type' => 1, + 'selection_can_change_qty' => 1, + ], + [ + 'sku' => $product3->getSku(), + 'selection_qty' => 1, + 'selection_price_value' => 25, + 'selection_price_type' => 0, + 'selection_can_change_qty' => 1, + ], +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, [$bundleSelectionsData]); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts_rollback.php new file mode 100644 index 0000000000000..d6a301c7937d6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/fixed_bundle_product_without_discounts_rollback.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Exception\NoSuchEntityException; + +require __DIR__ . '/multiple_products_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('fixed_bundle_product_without_discounts', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_different_price_products.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_different_price_products.php index 2e87e1e820f86..daa7f9f61a841 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_different_price_products.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_different_price_products.php @@ -15,20 +15,30 @@ use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Helper\DefaultCategory; $objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ $storeManager = $objectManager->get(StoreManagerInterface::class); +/** @var CategoryInterfaceFactory $categoryFactory */ $categoryFactory = $objectManager->get(CategoryInterfaceFactory::class); +/** @var ProductInterfaceFactory $productFactory */ $productFactory = $objectManager->get(ProductInterfaceFactory::class); +/** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var CategoryRepositoryInterface $categoryRepository */ $categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); +/** @var DefaultCategory $categoryHelper */ +$categoryHelper = $objectManager->get(DefaultCategory::class); $currentStoreId = $storeManager->getStore()->getId(); +$defaultWebsiteId = $storeManager->getWebsite('base')->getId(); $storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); $category = $categoryFactory->create(); $category->isObjectNew(true); $category->setName('Category 999') - ->setParentId(2) + ->setParentId($categoryHelper->getId()) ->setLevel(2) ->setAvailableSortBy('name') ->setDefaultSortBy('name') @@ -41,7 +51,7 @@ $product->setTypeId(Type::TYPE_SIMPLE) ->setAttributeSetId($product->getDefaultAttributeSetId()) ->setStoreId(Store::DEFAULT_STORE_ID) - ->setWebsiteIds([1]) + ->setWebsiteIds([$defaultWebsiteId]) ->setName('Simple Product With Price 10') ->setSku('simple1000') ->setPrice(10) @@ -52,11 +62,11 @@ ->setStatus(Status::STATUS_ENABLED); $productRepository->save($product); -$product = $productFactory->create(); -$product->setTypeId(Type::TYPE_SIMPLE) - ->setAttributeSetId($product->getDefaultAttributeSetId()) +$product2 = $productFactory->create(); +$product2->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($product2->getDefaultAttributeSetId()) ->setStoreId(Store::DEFAULT_STORE_ID) - ->setWebsiteIds([1]) + ->setWebsiteIds([$defaultWebsiteId]) ->setName('Simple Product With Price 20') ->setSku('simple1001') ->setPrice(20) @@ -65,4 +75,4 @@ ->setCategoryIds([$category->getId()]) ->setVisibility(Visibility::VISIBILITY_BOTH) ->setStatus(Status::STATUS_ENABLED); -$productRepository->save($product); +$productRepository->save($product2); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999.php new file mode 100644 index 0000000000000..32815134c78a1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface; +use Magento\CatalogRule\Api\Data\RuleInterface; +use Magento\CatalogRule\Api\Data\RuleInterfaceFactory; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\Rule\Condition\Combine; +use Magento\CatalogRule\Model\Rule\Condition\Product; +use Magento\Customer\Model\Group; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Catalog\Model\GetCategoryByName; + +$objectManager = Bootstrap::getObjectManager(); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$defaultWebsiteId = $websiteRepository->get('base')->getId(); +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); +/** @var CatalogRuleRepositoryInterface $catalogRuleRepository */ +$catalogRuleRepository = $objectManager->get(CatalogRuleRepositoryInterface::class); +/** @var RuleInterfaceFactory $ruleFactory */ +$catalogRuleFactory = $objectManager->get(RuleInterfaceFactory::class); +/** @var GetCategoryByName $getCategoryByName */ +$getCategoryByName = $objectManager->get(GetCategoryByName::class); + +$category = $getCategoryByName->execute('Category 999'); +if ($category->getId()) { + $ruleData = [ + RuleInterface::NAME => 'Catalog rule for category 999', + RuleInterface::IS_ACTIVE => 1, + 'website_ids' => [$defaultWebsiteId], + 'customer_group_ids' => Group::NOT_LOGGED_IN_ID, + RuleInterface::DISCOUNT_AMOUNT => 25, + RuleInterface::SIMPLE_ACTION => 'by_percent', + 'conditions' => [ + '1' => [ + 'type' => Combine::class, + 'aggregator' => 'all', + 'value' => '1', + ], + '1--1' => [ + 'type' => Product::class, + 'attribute' => 'category_ids', + 'operator' => '==', + 'value' => $category->getId(), + ], + ], + ]; + $catalogRule = $catalogRuleFactory->create(); + $catalogRule->loadPost($ruleData); + $catalogRuleRepository->save($catalogRule); + $indexBuilder->reindexFull(); +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999_rollback.php new file mode 100644 index 0000000000000..f7af2256575b8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_for_category_999_rollback.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var CatalogRuleRepositoryInterface $ruleRepository */ +$catalogRuleRepository = $objectManager->get(CatalogRuleRepositoryInterface::class); +/** @var CollectionFactory $ruleCollectionFactory */ +$ruleCollectionFactory = $objectManager->get(CollectionFactory::class); +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); + +$ruleCollection = $ruleCollectionFactory->create(); +$ruleCollection->addFieldToFilter('name', 'Catalog rule for category 999'); +$ruleCollection->setPageSize(1); +$catalogRule = $ruleCollection->getFirstItem(); +if ($catalogRule->getId()) { + $catalogRuleRepository->delete($catalogRule); +} +$indexBuilder->reindexFull(); From 18eaad44caa56f3913389486b6722715392b4a27 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Tue, 18 Feb 2020 10:32:50 +0200 Subject: [PATCH 39/43] MC-31528: Admin: Mass actions on customers grid --- .../Adminhtml/Index/InlineEditTest.php | 153 ++++++++++++++++++ .../Adminhtml/Index/MassUnsubscribeTest.php | 91 +++++++++++ .../Newsletter/_files/three_subscribers.php | 18 +++ .../_files/three_subscribers_rollback.php | 8 + 4 files changed, 270 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/InlineEditTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassUnsubscribeTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers.php create mode 100644 dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/InlineEditTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/InlineEditTest.php new file mode 100644 index 0000000000000..9879c8300f66c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/InlineEditTest.php @@ -0,0 +1,153 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Controller\Adminhtml\Index; + +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Eav\Model\AttributeRepository; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\AbstractBackendController; + +/** + * Test inline edit action on customers grid. + * + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + */ +class InlineEditTest extends AbstractBackendController +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var CustomerRepositoryInterface */ + private $customerRepository; + + /** @var SerializerInterface */ + private $json; + + /** @var WebsiteRepositoryInterface */ + private $websiteRepository; + + /** @var AttributeRepository */ + private $attributeRepository; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class); + $this->json = $this->objectManager->get(SerializerInterface::class); + $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); + $this->attributeRepository = $this->objectManager->get(AttributeRepository::class); + } + + /** + * @magentoDataFixture Magento/Customer/_files/two_customers.php + * + * @return void + */ + public function testInlineEditAction(): void + { + $firstCustomer = $this->customerRepository->get('customer@example.com'); + $secondCustomer = $this->customerRepository->get('customer_two@example.com'); + $defaultWebsiteId = $this->websiteRepository->get('base')->getId(); + $genderId = $this->attributeRepository->get(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, 'gender') + ->getSource()->getOptionId('Male'); + $params = [ + 'items' => [ + $firstCustomer->getId() => [ + CustomerInterface::EMAIL => 'updated_customer@example.com', + CustomerInterface::GROUP_ID => 2, + CustomerInterface::WEBSITE_ID => $defaultWebsiteId, + CustomerInterface::TAXVAT => 123123, + CustomerInterface::GENDER => $genderId, + ], + $secondCustomer->getId() => [ + CustomerInterface::EMAIL => 'updated_customer_two@example.com', + CustomerInterface::GROUP_ID => 3, + CustomerInterface::WEBSITE_ID => $defaultWebsiteId, + CustomerInterface::TAXVAT => 456456, + CustomerInterface::GENDER => $genderId, + ], + ], + 'isAjax' => true, + ]; + $actual = $this->performInlineEditRequest($params); + $this->assertEmpty($actual['messages']); + $this->assertFalse($actual['error']); + $this->assertCustomersData($params); + } + + /** + * @dataProvider inlineEditParametersDataProvider + * + * @param array $params + * @return void + */ + public function testInlineEditWithWrongParams(array $params): void + { + $actual = $this->performInlineEditRequest($params); + $this->assertEquals([(string)__('Please correct the data sent.')], $actual['messages']); + $this->assertTrue($actual['error']); + } + + /** + * @return array + */ + public function inlineEditParametersDataProvider(): array + { + return [ + [ + 'items' => [], + 'isAjax' => true, + ], + [ + 'items' => [], + ], + ]; + } + + /** + * Perform inline edit request. + * + * @param array $params + * @return array + */ + private function performInlineEditRequest(array $params): array + { + $this->getRequest()->setParams($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('backend/customer/index/inlineEdit'); + + return $this->json->unserialize($this->getResponse()->getBody()); + } + + /** + * Assert customers data. + * + * @param array $data + * @return void + */ + private function assertCustomersData(array $data): void + { + foreach ($data['items'] as $customerId => $expectedData) { + $customerData = $this->customerRepository->getById($customerId)->__toArray(); + foreach ($expectedData as $key => $value) { + $this->assertEquals($value, $customerData[$key]); + } + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassUnsubscribeTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassUnsubscribeTest.php new file mode 100644 index 0000000000000..586d06eb42b24 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassUnsubscribeTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Controller\Adminhtml\Index; + +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Message\MessageInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Newsletter\Model\ResourceModel\Subscriber\CollectionFactory; +use Magento\Newsletter\Model\Subscriber; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\TestFramework\TestCase\AbstractBackendController; + +/** + * Test mass subscribe action on customers grid. + * + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + */ +class MassUnsubscribeTest extends AbstractBackendController +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var CustomerRepositoryInterface */ + private $customerRepository; + + /** @var CollectionFactory */ + private $subscriberCollectionFactory; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->subscriberCollectionFactory = $this->objectManager->get(CollectionFactory::class); + $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class); + } + + /** + * @magentoDataFixture Magento/Newsletter/_files/three_subscribers.php + * + * @return void + */ + public function testMassUnsubscribeAction(): void + { + $params = [ + 'selected' => [1, 2, 3], + 'namespace' => 'customer_listing', + ]; + $this->getRequest()->setParams($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('backend/customer/index/massUnsubscribe'); + $this->assertRedirect($this->stringContains('backend/customer/index/index')); + $this->assertSessionMessages( + $this->equalTo([(string)__('A total of 3 record(s) were updated.')]), + MessageInterface::TYPE_SUCCESS + ); + $emails = ['customer@search.example.com', 'customer2@search.example.com', 'customer3@search.example.com']; + $collection = $this->subscriberCollectionFactory->create()->addFieldToFilter('subscriber_email', $emails) + ->addFieldToSelect('subscriber_status'); + $this->assertCount(3, $collection); + foreach ($collection as $subscriber) { + $this->assertEquals(Subscriber::STATUS_UNSUBSCRIBED, $subscriber->getData('subscriber_status')); + } + } + + /** + * @return void + */ + public function testMassSubscriberActionNoSelection(): void + { + $params = [ + 'namespace' => 'customer_listing', + ]; + $this->getRequest()->setParams($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('backend/customer/index/massUnsubscribe'); + $this->assertRedirect($this->stringContains('backend/customer/index/index')); + $this->assertSessionMessages( + $this->equalTo([(string)__('An item needs to be selected. Select and try again.')]), + MessageInterface::TYPE_ERROR + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers.php b/dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers.php new file mode 100644 index 0000000000000..5eb0ec5843bd8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Newsletter\Model\SubscriberFactory; +use Magento\TestFramework\Helper\Bootstrap; + +require __DIR__ . '/../../../Magento/Customer/_files/three_customers.php'; + +$objectManager = Bootstrap::getObjectManager(); +$subscriberFactory = $objectManager->get(SubscriberFactory::class); + +$subscriberFactory->create()->subscribe('customer@search.example.com'); +$subscriberFactory->create()->subscribe('customer2@search.example.com'); +$subscriberFactory->create()->subscribe('customer3@search.example.com'); diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers_rollback.php b/dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers_rollback.php new file mode 100644 index 0000000000000..e1760db7b1e52 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Newsletter/_files/three_subscribers_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +require __DIR__ . '/../../../Magento/Customer/_files/three_customers_rollback.php'; From d0f3da81c67f56e817cc85ae5e4cf954466ffe5f Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 18 Feb 2020 10:34:59 +0200 Subject: [PATCH 40/43] MC-31521: Customer login on storefront --- .../Magento/Customer/Block/Form/LoginTest.php | 92 ++++++++++ .../Controller/Account/LoginPostTest.php | 171 ++++++++++++++++++ .../Customer/Controller/AccountTest.php | 115 ------------ .../Customer/_files/unconfirmed_customer.php | 47 +++++ .../_files/unconfirmed_customer_rollback.php | 33 ++++ 5 files changed, 343 insertions(+), 115 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Block/Form/LoginTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Account/LoginPostTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Form/LoginTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Form/LoginTest.php new file mode 100644 index 0000000000000..f500885a35ed2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Form/LoginTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Block\Form; + +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\LayoutInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use PHPUnit\Framework\TestCase; + +/** + * Class checks login form view + * + * @magentoAppArea frontend + */ +class LoginTest extends TestCase +{ + private const EMAIL_LABEL_XPATH = "//label[@for='email']/span[contains(text(), 'Email')]"; + private const PASSWORD_LABEL_XPATH = "//label[@for='pass' ]/span[contains(text(), 'Password')]"; + private const EMAIL_INPUT_XPATH = "//input[@name ='login[username]' and contains(@data-validate,'required:true')" + . "and contains(@data-validate, \"'validate-email':true\")]"; + private const PASSWORD_INPUT_XPATH = "//input[@name='login[password]'" + . "and contains(@data-validate,'required:true')]"; + private const SIGN_IN_BUTTON_XPATH = "//button[@type='submit']/span[contains(text(), 'Sign In')]"; + private const FORGOT_PASSWORD_LINK_PATH = "//a[contains(@href, 'customer/account/forgotpassword')]" + . "/span[contains(text(), 'Forgot Your Password?')] "; + + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var LayoutInterface */ + private $layout; + + /** @var Login */ + private $block; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->layout = $this->objectManager->get(LayoutInterface::class); + $this->block = $this->layout->createBlock(Login::class); + $this->block->setTemplate('Magento_Customer::form/login.phtml'); + + parent::setUp(); + } + + /** + * @return void + */ + public function testLoginForm(): void + { + $result = $this->block->toHtml(); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath(self::EMAIL_LABEL_XPATH, $result), + 'Email label does not exist on the page' + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath(self::PASSWORD_LABEL_XPATH, $result), + 'Password label does not exist on the page' + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath(self::EMAIL_INPUT_XPATH, $result), + 'Email input does not exist on the page' + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath(self::PASSWORD_INPUT_XPATH, $result), + 'Password input does not exist on the page' + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath(self::SIGN_IN_BUTTON_XPATH, $result), + 'Sign in button does not exist on the page' + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath(self::FORGOT_PASSWORD_LINK_PATH, $result), + 'Forgot password link does not exist on the page' + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Account/LoginPostTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Account/LoginPostTest.php new file mode 100644 index 0000000000000..80502833cb2d7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Account/LoginPostTest.php @@ -0,0 +1,171 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Controller\Account; + +use Magento\Customer\Model\Session; +use Magento\Customer\Model\Url; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Message\MessageInterface; +use Magento\Framework\Url\EncoderInterface; +use Magento\TestFramework\TestCase\AbstractController; + +/** + * Class checks customer login action + * + * @see \Magento\Customer\Controller\Account\LoginPost + */ +class LoginPostTest extends AbstractController +{ + /** @var Session */ + private $session; + + /** @var EncoderInterface */ + private $urlEncoder; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->session = $this->_objectManager->get(Session::class); + $this->urlEncoder = $this->_objectManager->get(EncoderInterface::class); + } + + /** + * @magentoConfigFixture current_store customer/captcha/enable 0 + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @dataProvider missingParametersDataProvider + * + * @param string|null $email + * @param string|null $password + * @param string $expectedErrorMessage + * @return void + */ + public function testLoginIncorrectParameters(?string $email, ?string $password, string $expectedErrorMessage): void + { + $this->prepareRequest($email, $password); + $this->dispatch('customer/account/loginPost'); + $this->assertSessionMessages( + $this->equalTo([(string)__($expectedErrorMessage)]), + MessageInterface::TYPE_ERROR + ); + } + + /** + * @return array + */ + public function missingParametersDataProvider(): array + { + return [ + 'missing_email' => [ + 'email' => null, + 'password' => 'password', + 'expected_error_message' => 'A login and a password are required.', + ], + 'missing_password' => [ + 'email' => 'customer@example.com', + 'password' => null, + 'expected_error_message' => 'A login and a password are required.', + ], + 'missing_both_parameters' => [ + 'email' => null, + 'password' => null, + 'expected_error_message' => 'A login and a password are required.', + ], + 'wrong_email' => [ + 'email' => 'wrongemail@example.com', + 'password' => 'password', + 'expected_error_message' => 'The account sign-in was incorrect or your account is disabled temporarily.' + . ' Please wait and try again later.', + ], + 'wrong_password' => [ + 'email' => 'customer@example.com', + 'password' => 'wrongpassword', + 'expected_error_message' => 'The account sign-in was incorrect or your account is disabled temporarily.' + . ' Please wait and try again later.', + ], + ]; + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_confirmation_config_enable.php + * @magentoDataFixture Magento/Customer/_files/unconfirmed_customer.php + * + * @magentoConfigFixture current_store customer/captcha/enable 0 + * + * @return void + */ + public function testLoginWithUnconfirmedPassword(): void + { + $this->markTestSkipped('Blocked by MC-31370.'); + $email = 'unconfirmedcustomer@example.com'; + $this->prepareRequest($email, 'Qwert12345'); + $this->dispatch('customer/account/loginPost'); + $this->assertEquals($email, $this->session->getUsername()); + $this->assertSessionMessages( + $this->equalTo([(string)__('This account is not confirmed. Click here to resend confirmation email.')]), + MessageInterface::TYPE_ERROR + ); + } + + /** + * @magentoConfigFixture current_store customer/startup/redirect_dashboard 0 + * @magentoConfigFixture current_store customer/captcha/enable 0 + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testLoginWithRedirectToDashboardDisabled(): void + { + $this->prepareRequest('customer@example.com', 'password'); + $this->getRequest()->setParam(Url::REFERER_QUERY_PARAM_NAME, $this->urlEncoder->encode('test_redirect')); + $this->dispatch('customer/account/loginPost'); + $this->assertTrue($this->session->isLoggedIn()); + $this->assertRedirect($this->stringContains('test_redirect')); + } + + /** + * @magentoConfigFixture current_store customer/startup/redirect_dashboard 1 + * @magentoConfigFixture current_store customer/captcha/enable 0 + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testLoginWithRedirectToDashboard(): void + { + $this->prepareRequest('customer@example.com', 'password'); + $this->getRequest()->setParam(Url::REFERER_QUERY_PARAM_NAME, $this->urlEncoder->encode('test_redirect')); + $this->dispatch('customer/account/loginPost'); + $this->assertTrue($this->session->isLoggedIn()); + $this->assertRedirect($this->stringContains('customer/account/')); + } + + /** + * Prepare request + * + * @param string|null $email + * @param string|null $password + * @return void + */ + private function prepareRequest(?string $email, ?string $password): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue([ + 'login' => [ + 'username' => $email, + 'password' => $password, + ], + ]); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index 18f9b2d2cb737..076f9585788cc 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -8,13 +8,10 @@ use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\Data\CustomerInterface; -use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\CustomerRegistry; use Magento\Customer\Model\Session; use Magento\Framework\Api\FilterBuilder; use Magento\Framework\Api\SearchCriteriaBuilder; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\App\Config\Value; use Magento\Framework\App\Http; use Magento\Framework\App\Request\Http as HttpRequest; use Magento\Framework\Data\Form\FormKey; @@ -26,10 +23,8 @@ use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Mail\Template\TransportBuilderMock; use Magento\TestFramework\Request; -use Magento\TestFramework\Response; use Magento\Theme\Controller\Result\MessagePlugin; use PHPUnit\Framework\Constraint\StringContains; -use Zend\Stdlib\Parameters; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -77,35 +72,6 @@ public function testIndexAction() $this->assertContains('Green str, 67', $body); } - /** - * @magentoDataFixture Magento/Customer/_files/customer_no_password.php - */ - public function testLoginWithIncorrectPassword() - { - $expectedMessage = 'The account sign-in was incorrect or your account is disabled temporarily. ' - . 'Please wait and try again later.'; - $this->getRequest() - ->setMethod('POST') - ->setPostValue( - [ - 'login' => [ - 'username' => 'customer@example.com', - 'password' => '123123q' - ] - ] - ); - - $this->dispatch('customer/account/loginPost'); - $this->assertRedirect($this->stringContains('customer/account/login')); - $this->assertSessionMessages( - $this->equalTo( - [ - $expectedMessage - ] - ) - ); - } - /** * Test sign up form displaying. */ @@ -640,35 +606,6 @@ public function testWrongConfirmationEditPostAction() ); } - /** - * Test redirect customer to account dashboard after logging in. - * - * @param bool|null $redirectDashboard - * @param string $redirectUrl - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled - * @magentoDataFixture Magento/Customer/_files/customer.php - * @dataProvider loginPostRedirectDataProvider - */ - public function testLoginPostRedirect($redirectDashboard, string $redirectUrl) - { - if (isset($redirectDashboard)) { - $this->_objectManager->get(ScopeConfigInterface::class)->setValue( - 'customer/startup/redirect_dashboard', - $redirectDashboard - ); - } - $this->_objectManager->get(Redirect::class)->setRedirectCookie('test'); - $configValue = $this->_objectManager->create(Value::class); - $configValue->load('web/unsecure/base_url', 'path'); - $baseUrl = $configValue->getValue() ?: 'http://localhost/'; - $request = $this->prepareRequest(); - $app = $this->_objectManager->create(Http::class, ['_request' => $request]); - $response = $app->launch(); - $this->assertResponseRedirect($response, $baseUrl . $redirectUrl); - $this->assertTrue($this->_objectManager->get(Session::class)->isLoggedIn()); - } - /** * Register Customer with email confirmation. * @@ -915,20 +852,6 @@ private function resetRequest(): void $this->_request = null; } - /** - * Data provider for testLoginPostRedirect. - * - * @return array - */ - public function loginPostRedirectDataProvider() - { - return [ - [null, 'index.php/'], - [0, 'index.php/'], - [1, 'index.php/customer/account/'], - ]; - } - /** * @param string $email * @return void @@ -997,44 +920,6 @@ private function getCustomerByEmail($email) return $customer; } - /** - * Prepare request for customer login. - * - * @return Request - */ - private function prepareRequest() - { - $post = new Parameters( - [ - 'form_key' => $this->_objectManager->get(FormKey::class)->getFormKey(), - 'login' => [ - 'username' => 'customer@example.com', - 'password' => 'password' - ] - ] - ); - $request = $this->getRequest(); - $formKey = $this->_objectManager->get(FormKey::class); - $request->setParam('form_key', $formKey->getFormKey()); - $request->setMethod(Request::METHOD_POST); - $request->setRequestUri('customer/account/loginPost/'); - $request->setPost($post); - return $request; - } - - /** - * Assert response is redirect. - * - * @param Response $response - * @param string $redirectUrl - * @return void - */ - private function assertResponseRedirect(Response $response, string $redirectUrl) - { - $this->assertTrue($response->isRedirect()); - $this->assertSame($redirectUrl, $response->getHeader('Location')->getUri()); - } - /** * Add new request info (request uri, path info, action name). * diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer.php b/dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer.php new file mode 100644 index 0000000000000..3aad592ad34ef --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Api\CustomerMetadataInterface; +use \Magento\Customer\Model\Data\CustomerFactory; +use Magento\Eav\Model\AttributeRepository; +use Magento\Framework\Math\Random; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var AccountManagementInterface $accountManagment */ +$accountManagment = $objectManager->get(AccountManagementInterface::class); +/** @var CustomerFactory $customerFactory */ +$customerFactory = $objectManager->get(CustomerFactory::class); +/** @var Random $random */ +$random = $objectManager->get(Random::class); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$customer = $customerFactory->create(); +$website = $websiteRepository->get('base'); +$defaultStoreId = $website->getDefaultStore()->getId(); +/** @var AttributeRepository $attributeRepository */ +$attributeRepository = $objectManager->get(AttributeRepository::class); +$gender = $attributeRepository->get(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, 'gender') + ->getSource()->getOptionId('Male'); + +$customer->setWebsiteId($website->getId()) + ->setEmail('unconfirmedcustomer@example.com') + ->setGroupId(1) + ->setStoreId($defaultStoreId) + ->setPrefix('Mr.') + ->setFirstname('John') + ->setMiddlename('A') + ->setLastname('Smith') + ->setSuffix('Esq.') + ->setDefaultBilling(1) + ->setDefaultShipping(1) + ->setConfirmation($random->getUniqueHash()) + ->setGender($gender); + +$accountManagment->createAccount($customer, 'Qwert12345'); diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer_rollback.php b/dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer_rollback.php new file mode 100644 index 0000000000000..cbe30d4d24fcb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/unconfirmed_customer_rollback.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Registry; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$websiteId = $websiteRepository->get('base')->getId(); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $customer = $customerRepository->get('unconfirmedcustomer@example.com', $websiteId); + $customerRepository->delete($customer); +} catch (NoSuchEntityException $e) { + //customer already deleted +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 5bd23493e4227fc951fd71e5181b40d5e1c83463 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola <mykhailo.matiola@transoftgroup.com> Date: Thu, 20 Feb 2020 09:13:09 +0200 Subject: [PATCH 41/43] MC-31531: Storefront: View configurable product with related, up-sells products --- .../Block/Product/ProductList/RelatedTest.php | 114 ++++++++++++++++++ .../Block/Product/ProductList/UpsellTest.php | 43 +++++++ 2 files changed, 157 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/RelatedTest.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/UpsellTest.php diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/RelatedTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/RelatedTest.php new file mode 100644 index 0000000000000..8543b2600138b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/RelatedTest.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\ConfigurableProduct\Block\Product\ProductList; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Block\Product\ProductList\AbstractLinksTest; +use Magento\Catalog\Block\Product\ProductList\Related; + +/** + * Check the correct behavior of related products on the configurable product view page + + * @magentoDbIsolation disabled + * @magentoAppArea frontend + */ +class RelatedTest extends AbstractLinksTest +{ + /** + * @var Related + */ + protected $block; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->block = $this->layout->createBlock(Related::class); + $this->linkType = 'related'; + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @return void + */ + public function testRenderConfigurableWithLinkedProduct(): void + { + $this->linkProducts('configurable', ['simple2' => ['position' => 1]]); + $relatedProduct = $this->productRepository->get('simple2'); + $this->block->setProduct($this->productRepository->get('configurable')); + $this->prepareBlock(); + $html = $this->block->toHtml(); + $this->assertNotEmpty($html); + $this->assertContains($relatedProduct->getName(), $html); + $this->assertCount(1, $this->block->getItems()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @return void + */ + public function testRenderConfigurableWithLinkedProductOnChild(): void + { + $this->linkProducts('simple_10', ['simple2' => ['position' => 1]]); + $relatedProduct = $this->productRepository->get('simple2'); + $this->block->setProduct($this->productRepository->get('configurable')); + $this->prepareBlock(); + $html = $this->block->toHtml(); + $this->assertNotEmpty($html); + $this->assertNotContains($relatedProduct->getName(), $html); + $this->assertEmpty($this->block->getItems()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/products_list.php + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @return void + */ + public function testLinkedProductsPosition(): void + { + $this->linkProducts( + 'configurable', + ['wrong-simple' => ['position' => 3], 'simple-249' => ['position' => 2], 'simple-156' => ['position' => 1]] + ); + $this->block->setProduct($this->productRepository->get('configurable')); + $this->assertEquals( + ['simple-156', 'simple-249','wrong-simple'], + $this->getActualLinks($this->getLinkedItems()), + 'Expected linked products do not match actual linked products!' + ); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @return void + */ + public function testGetIdentities(): void + { + $this->linkProducts('configurable', ['simple2' => ['position = 1']]); + $relatedProduct = $this->productRepository->get('simple2'); + $this->block->setProduct($this->productRepository->get('configurable')); + $this->prepareBlock(); + $this->assertEquals(['cat_p_' . $relatedProduct->getId(), 'cat_p'], $this->block->getIdentities()); + } + + /** + * Returns linked products from block. + * + * @return ProductInterface[] + */ + protected function getLinkedItems(): array + { + return $this->block->getItems()->getItems(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/UpsellTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/UpsellTest.php new file mode 100644 index 0000000000000..ad24b84533c79 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/ProductList/UpsellTest.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\ConfigurableProduct\Block\Product\ProductList; + +use Magento\Catalog\Block\Product\ProductList\Upsell; + +/** + * Check the correct behavior of up-sell products on the configurable product view page + * + * @magentoDbIsolation disabled + * @magentoAppArea frontend + */ +class UpsellTest extends RelatedTest +{ + /** + * @var Upsell + */ + protected $block; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->block = $this->layout->createBlock(Upsell::class); + $this->linkType = 'upsell'; + } + + /** + * @inheritdoc + */ + protected function getLinkedItems(): array + { + return $this->block->getItems(); + } +} From 23b2279d2783b65c6380cd20210bfa2f250aeb6b Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 20 Feb 2020 18:30:18 -0600 Subject: [PATCH 42/43] MQE-2003: Bump MFTF version in Magento fixed flaky test --- .../Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml index 685385382027b..3a39fe3218d96 100644 --- a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml @@ -20,6 +20,7 @@ <fillField selector="{{BlockNewPageBasicFieldsSection.blockTitle}}" userInput="{{cmsBlockDataTitle}}" stepKey="fillFieldTitle1"/> <fillField selector="{{BlockNewPageBasicFieldsSection.identifier}}" userInput="{{cmsBlockDataIdentifier}}" stepKey="fillFieldIdentifier"/> <selectOption selector="{{BlockNewPageBasicFieldsSection.storeView}}" userInput="All Store View" stepKey="selectAllStoreView"/> + <scrollTo selector="{{BlockContentSection.TextArea}}" stepKey="scrollToContentField"/> <fillField selector="{{BlockContentSection.TextArea}}" userInput="{{cmsBlockDataContent}}" stepKey="fillContentField"/> </actionGroup> </actionGroups> From 1ebf6fa78f9b2d6c04197cb11a04f4c43df4fee5 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Fri, 21 Feb 2020 00:35:31 -0600 Subject: [PATCH 43/43] MQE-2003: Bump MFTF version in Magento Added WYSIWYGDisabled group --- .../Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml | 1 - app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml | 2 +- .../Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml | 2 +- app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsPageTest.xml | 2 +- .../Cms/Test/Mftf/Test/AdminCreateDuplicatedCmsPageTest.xml | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml index 3a39fe3218d96..685385382027b 100644 --- a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml @@ -20,7 +20,6 @@ <fillField selector="{{BlockNewPageBasicFieldsSection.blockTitle}}" userInput="{{cmsBlockDataTitle}}" stepKey="fillFieldTitle1"/> <fillField selector="{{BlockNewPageBasicFieldsSection.identifier}}" userInput="{{cmsBlockDataIdentifier}}" stepKey="fillFieldIdentifier"/> <selectOption selector="{{BlockNewPageBasicFieldsSection.storeView}}" userInput="All Store View" stepKey="selectAllStoreView"/> - <scrollTo selector="{{BlockContentSection.TextArea}}" stepKey="scrollToContentField"/> <fillField selector="{{BlockContentSection.TextArea}}" userInput="{{cmsBlockDataContent}}" stepKey="fillContentField"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml index 6867560551915..7e7d942140645 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml @@ -17,10 +17,10 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-89185"/> <group value="Cms"/> + <group value="WYSIWYGDisabled"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> - <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> </before> <after> <actionGroup ref="deleteBlock" stepKey="deleteCreatedBlock"> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml index 0399d0eb3ab28..97fac85aac81c 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml @@ -16,10 +16,10 @@ <description value="Admin can not able create a CMS block with marginal space in identifier field"/> <severity value="CRITICAL"/> <group value="Cms"/> + <group value="WYSIWYGDisabled"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> - <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> </before> <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnBlocksCreationForm"/> <waitForPageLoad stepKey="waitForPageLoad1"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsPageTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsPageTest.xml index 7fd39ab5bb1d6..82bcb295c2a9a 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsPageTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsPageTest.xml @@ -17,10 +17,10 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-25580"/> <group value="Cms"/> + <group value="WYSIWYGDisabled"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> - <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> </before> <after> <actionGroup ref="logout" stepKey="adminLogout"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateDuplicatedCmsPageTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateDuplicatedCmsPageTest.xml index cf333f8b559d0..5c5fccf761aa1 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateDuplicatedCmsPageTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateDuplicatedCmsPageTest.xml @@ -17,10 +17,10 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-89184"/> <group value="Cms"/> + <group value="WYSIWYGDisabled"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> - <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> </before> <after> <actionGroup ref="logout" stepKey="logout"/>