From c5ebd86cd9dacc368ae4b09af04fdac1b66cfb6f Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Thu, 12 Apr 2018 14:30:17 -0500 Subject: [PATCH 001/118] MAGETWO-88391: [MFTF CE Tests] EnabledWYSIWYG and DisabledWYSIWYG action groups should not use hardcoded backend name - Updated ActionGroup to use non-hardcoded paths --- .../Config/ActionGroup/ConfigWYSIWYGActionGroup.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml index 11d7acc61d75e..6867efd81c7ba 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml @@ -9,7 +9,7 @@ - + @@ -20,7 +20,7 @@ - + From bd52ab0f98bc97c0cf7491569a3f5fd9fa86ed49 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Fri, 13 Apr 2018 08:17:09 -0500 Subject: [PATCH 002/118] MAGETWO-87436: Unstable Mainline Test Magento\SalesRule\Model\Rule\Condition\ProductTest::testValidateCategorySalesRuleIncludesChildren - Unskipped unstable test to try and reproduce on Bamboo --- .../Magento/SalesRule/Model/Rule/Condition/ProductTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php index 158cc3da2d0cd..7fe55499bf26e 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php @@ -28,14 +28,13 @@ protected function setUp() * @magentoAppIsolation enabled * @param int $categoryId * @param bool $expectedResult + * + * @magentoDataFixture Magento/ConfigurableProduct/_files/quote_with_configurable_product.php + * @magentoDataFixture Magento/SalesRule/_files/rules_category.php * @dataProvider validateProductConditionDataProvider */ public function testValidateCategorySalesRuleIncludesChildren($categoryId, $expectedResult) { - //* @magentoDataFixture Magento/ConfigurableProduct/_files/quote_with_configurable_product.php - //* @magentoDataFixture Magento/SalesRule/_files/rules_category.php - $this->markTestSkipped('MAGETWO-87436'); - // Load the quote that contains a child of a configurable product /** @var \Magento\Quote\Model\Quote $quote */ $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class) From 0748adac26f171f8daba87b70d36176ef5b82ade Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar Date: Sat, 12 May 2018 13:28:48 +0200 Subject: [PATCH 003/118] Drop foreign key referencing admin_user table from bulk operations. Pass the Web API user id taken from the context object to MassScheduler --- .../AsynchronousOperations/Model/MassSchedule.php | 14 +++++++++++++- .../AsynchronousOperations/etc/db_schema.xml | 4 +--- .../etc/db_schema_whitelist.json | 1 - 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php index 2d516e82f4016..f722927e452a9 100644 --- a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php +++ b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php @@ -18,6 +18,7 @@ use Magento\Framework\Exception\BulkException; use Psr\Log\LoggerInterface; use Magento\AsynchronousOperations\Model\ResourceModel\Operation\OperationRepository; +use Magento\Authorization\Model\UserContextInterface; /** * Class MassSchedule used for adding multiple entities as Operations to Bulk Management with the status tracking @@ -54,6 +55,11 @@ class MassSchedule */ private $operationRepository; + /** + * @var \Magento\Webapi\Model\Authorization\TokenUserContext + */ + private $userContext; + /** * Initialize dependencies. * @@ -70,7 +76,8 @@ public function __construct( AsyncResponseInterfaceFactory $asyncResponseFactory, BulkManagementInterface $bulkManagement, LoggerInterface $logger, - OperationRepository $operationRepository + OperationRepository $operationRepository, + UserContextInterface $userContext ) { $this->identityService = $identityService; $this->itemStatusInterfaceFactory = $itemStatusInterfaceFactory; @@ -78,6 +85,7 @@ public function __construct( $this->bulkManagement = $bulkManagement; $this->logger = $logger; $this->operationRepository = $operationRepository; + $this->userContext = $userContext; } /** @@ -95,6 +103,10 @@ public function publishMass($topicName, array $entitiesArray, $groupId = null, $ { $bulkDescription = __('Topic %1', $topicName); + if ($userId == null) { + $userId = $this->userContext->getUserId(); + } + if ($groupId == null) { $groupId = $this->identityService->generateId(); diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml index 1b99ce9a2805f..a3acb7897580f 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml @@ -14,7 +14,7 @@ + comment="ID of the WebAPI user that performed an action"/> @@ -23,8 +23,6 @@ - diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json index 396e443355d8f..6b18ac3e29d43 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json @@ -10,7 +10,6 @@ }, "constraint": { "PRIMARY": true, - "MAGENTO_BULK_USER_ID_ADMIN_USER_USER_ID": true, "MAGENTO_BULK_UUID": true } }, From 55fb63667d51f416dd5cf7b31f92a84474fbeb04 Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar Date: Sat, 12 May 2018 15:15:32 +0200 Subject: [PATCH 004/118] Drop foreign key referencing admin_user table from bulk operations. Pass the Web API user id taken from the context object to MassScheduler --- app/code/Magento/AsynchronousOperations/Model/MassSchedule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php index f722927e452a9..5f792d1729ca4 100644 --- a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php +++ b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php @@ -56,7 +56,7 @@ class MassSchedule private $operationRepository; /** - * @var \Magento\Webapi\Model\Authorization\TokenUserContext + * @var \Magento\Authorization\Model\UserContextInterface */ private $userContext; From 4e7c3cbd5d64d299965ff258cab84b11c3d6379d Mon Sep 17 00:00:00 2001 From: Roman Ganin Date: Tue, 19 Jun 2018 15:36:06 -0500 Subject: [PATCH 005/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some --- app/code/Magento/Sales/Model/Order/Item.php | 2 +- app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php index d2f5f5ce56692..7fa2f61554563 100644 --- a/app/code/Magento/Sales/Model/Order/Item.php +++ b/app/code/Magento/Sales/Model/Order/Item.php @@ -232,7 +232,7 @@ public function getQtyToShip() */ public function getSimpleQtyToShip() { - $qty = $this->getQtyOrdered() - $this->getQtyShipped() - $this->getQtyRefunded() - $this->getQtyCanceled(); + $qty = $this->getQtyOrdered() - $this->getQtyShipped() - $this->getQtyCanceled(); return max(round($qty, 8), 0); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php index 39fffa23dc1ec..956152d2e0858 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php @@ -292,14 +292,14 @@ public function getItemQtyVariants() 'qty_ordered' => 12, 'qty_invoiced' => 5, 'qty_refunded' => 5, 'qty_shipped' => 0, 'qty_canceled' => 0, ], - 'expectedResult' => ['to_ship' => 7.0, 'to_invoice' => 7.0] + 'expectedResult' => ['to_ship' => 12.0, 'to_invoice' => 7.0] ], 'partially_refunded' => [ 'options' => [ 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 5, 'qty_shipped' => 0, 'qty_canceled' => 0, ], - 'expectedResult' => ['to_ship' => 7.0, 'to_invoice' => 0.0] + 'expectedResult' => ['to_ship' => 12.0, 'to_invoice' => 0.0] ], 'partially_shipped' => [ 'options' => [ @@ -313,7 +313,7 @@ public function getItemQtyVariants() 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 5, 'qty_shipped' => 4, 'qty_canceled' => 0 ], - 'expectedResult' => ['to_ship' => 3.0, 'to_invoice' => 0.0] + 'expectedResult' => ['to_ship' => 8.0, 'to_invoice' => 0.0] ], 'complete' => [ 'options' => [ @@ -334,7 +334,7 @@ public function getItemQtyVariants() 'qty_ordered' => 4.4, 'qty_invoiced' => 0.4, 'qty_refunded' => 0.4, 'qty_shipped' => 4, 'qty_canceled' => 0, ], - 'expectedResult' => ['to_ship' => 0.0, 'to_invoice' => 4.0] + 'expectedResult' => ['to_ship' => 0.4, 'to_invoice' => 4.0] ], 'completely_invoiced_using_decimals' => [ 'options' => [ From a73786b1a1342f43977af2f7ad01fd402c77cfd4 Mon Sep 17 00:00:00 2001 From: Deepty Thampy Date: Wed, 27 Jun 2018 16:26:09 -0500 Subject: [PATCH 006/118] MAGETWO-60034: Cannot ship remaining items nan order for several of one product if credit memo is made for some - added functional test --- ...inAbleToShipPartiallyInvoicedItemsTest.xml | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml new file mode 100644 index 0000000000000..0f5346e619a09 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -0,0 +1,76 @@ + + + + + + + <description value="Admin should not be able to submit orders without an email address"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-60034"/> + <group value="sales"/> + + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + <!--Create order via Admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <comment userInput="Admin creates order" stepKey="adminCreateOrderComment"/> + <!--<actionGroup ref="navigateToNewOrderPageNewCustomer" stepKey="navigateToNewOrderPage"/>--> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="navigateToOrderIndexPage"/> + <waitForPageLoad stepKey="waitForIndexPageLoad"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Orders" stepKey="seeIndexPageTitle"/> + <click selector="{{AdminOrdersGridSection.createNewOrder}}" stepKey="clickCreateNewOrder"/> + <click selector="{{AdminOrderFormActionSection.CreateNewCustomer}}" stepKey="clickCreateCustomer"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Create New Order" stepKey="seeNewOrderPageTitle"/> + <!--<actionGroup ref="checkRequiredFieldsNewOrderForm" stepKey="checkRequiredFieldsNewOrder" after="seeNewOrderPageTitle"/>--> + <!--<scrollToTopOfPage stepKey="scrollToTopOfOrderFormPage" after="checkRequiredFieldsNewOrder"/>--> + <actionGroup ref="addSimpleProductToOrderWithCustomQuantity" stepKey="addSimpleProductToOrderWithUserDefinedQty"> + <argument name="product" value="_defaultProduct"/> + <argument name="quantity" value="10"/> + </actionGroup> + + <!--Fill customer group and customer email which both are now required fields--> + <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> + <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail" after="selectCustomerGroup"/> + + <!--Fill customer address information--> + <actionGroup ref="fillOrderCustomerInformation" stepKey="fillCustomerAddress" after="fillCustomerEmail"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="address" value="US_Address_TX"/> + </actionGroup> + <!-- Select shipping --> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping" after="fillCustomerAddress"/> + + <!--Verify totals on Order page--> + <see selector="{{AdminOrderFormTotalSection.total('Subtotal')}}" userInput="$1230.00" stepKey="seeOrderSubTotal" after="selectFlatRateShipping"/> + <see selector="{{AdminOrderFormTotalSection.total('Shipping')}}" userInput="$50.00" stepKey="seeOrderShipping" after="seeOrderSubTotal"/> + <scrollTo selector="{{AdminOrderFormTotalSection.grandTotal}}" stepKey="scrollToOrderGrandTotal"/> + <see selector="{{AdminOrderFormTotalSection.grandTotal}}" userInput="$1280.00" stepKey="seeCorrectGrandTotal" after="scrollToOrderGrandTotal"/> + + <!--Submit Order and verify information--> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder" after="seeCorrectGrandTotal"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPage" after="clickSubmitOrder"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeSuccessMessage" after="seeViewOrderPage"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.qtyColumn}}" stepKey="scrollToItemsOrdered" after="seeSuccessMessage"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Ordered 10" stepKey="seeQtyOfItemsOrdered" after="scrollToItemsOrdered"/> + + + + </test> +</tests> + From 228eaee9f918a136994c54a6e5e3e4eb1269ef4b Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@magento.com> Date: Thu, 28 Jun 2018 15:27:52 -0500 Subject: [PATCH 007/118] MAGETWO-60034: Cannot ship remaining items nan order for several of one product if credit memo is made for some - added functional test and updated actionGroup --- .../ActionGroup/AdminOrderActionGroup.xml | 18 +++ ...inAbleToShipPartiallyInvoicedItemsTest.xml | 109 ++++++++++++++++-- .../Section/AdminShipmentItemsSection.xml | 2 +- 3 files changed, 120 insertions(+), 9 deletions(-) diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml index 7461d9010a024..a27ee27c0b8c3 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml @@ -60,6 +60,24 @@ <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> </actionGroup> + <!--Add a simple product to order with user defined quantity--> + <actionGroup name="addSimpleProductToOrderWithCustomQuantity"> + <arguments> + <argument name="product" defaultValue="_defaultProduct"/> + <argument name="quantity" type="string"/> + </arguments> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMastToDisappear"/> + <waitForElementVisible selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="waitForAddProductButton"/> + <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> + <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilter"/> + <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearch"/> + <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> + <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> + <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="{{quantity}}" stepKey="fillProductQty"/> + <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + </actionGroup> + <!--Add configurable product to order --> <actionGroup name="addConfigurableProductToOrder"> <arguments> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 0f5346e619a09..c477fabe04828 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -27,25 +27,25 @@ <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> </after> - <!--Create order via Admin--> + + <!--login to Admin--> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> <comment userInput="Admin creates order" stepKey="adminCreateOrderComment"/> - <!--<actionGroup ref="navigateToNewOrderPageNewCustomer" stepKey="navigateToNewOrderPage"/>--> <amOnPage url="{{AdminOrdersPage.url}}" stepKey="navigateToOrderIndexPage"/> <waitForPageLoad stepKey="waitForIndexPageLoad"/> <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Orders" stepKey="seeIndexPageTitle"/> + + <!--Create new order--> <click selector="{{AdminOrdersGridSection.createNewOrder}}" stepKey="clickCreateNewOrder"/> <click selector="{{AdminOrderFormActionSection.CreateNewCustomer}}" stepKey="clickCreateCustomer"/> <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Create New Order" stepKey="seeNewOrderPageTitle"/> - <!--<actionGroup ref="checkRequiredFieldsNewOrderForm" stepKey="checkRequiredFieldsNewOrder" after="seeNewOrderPageTitle"/>--> - <!--<scrollToTopOfPage stepKey="scrollToTopOfOrderFormPage" after="checkRequiredFieldsNewOrder"/>--> <actionGroup ref="addSimpleProductToOrderWithCustomQuantity" stepKey="addSimpleProductToOrderWithUserDefinedQty"> <argument name="product" value="_defaultProduct"/> <argument name="quantity" value="10"/> </actionGroup> <!--Fill customer group and customer email which both are now required fields--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> + <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="addSimpleProductToOrderWithUserDefinedQty"/> <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail" after="selectCustomerGroup"/> <!--Fill customer address information--> @@ -57,20 +57,113 @@ <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping" after="fillCustomerAddress"/> <!--Verify totals on Order page--> - <see selector="{{AdminOrderFormTotalSection.total('Subtotal')}}" userInput="$1230.00" stepKey="seeOrderSubTotal" after="selectFlatRateShipping"/> + <see selector="{{AdminOrderFormTotalSection.total('Subtotal')}}" userInput="$1,230.00" stepKey="seeOrderSubTotal" after="selectFlatRateShipping"/> <see selector="{{AdminOrderFormTotalSection.total('Shipping')}}" userInput="$50.00" stepKey="seeOrderShipping" after="seeOrderSubTotal"/> <scrollTo selector="{{AdminOrderFormTotalSection.grandTotal}}" stepKey="scrollToOrderGrandTotal"/> - <see selector="{{AdminOrderFormTotalSection.grandTotal}}" userInput="$1280.00" stepKey="seeCorrectGrandTotal" after="scrollToOrderGrandTotal"/> + <see selector="{{AdminOrderFormTotalSection.grandTotal}}" userInput="$1,280.00" stepKey="seeCorrectGrandTotal" after="scrollToOrderGrandTotal"/> <!--Submit Order and verify information--> <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder" after="seeCorrectGrandTotal"/> <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPage" after="clickSubmitOrder"/> <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeSuccessMessage" after="seeViewOrderPage"/> - <scrollTo selector="{{AdminOrderItemsOrderedSection.qtyColumn}}" stepKey="scrollToItemsOrdered" after="seeSuccessMessage"/> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId" after="seeSuccessMessage"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.qtyColumn}}" stepKey="scrollToItemsOrdered" after="getOrderId"/> <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Ordered 10" stepKey="seeQtyOfItemsOrdered" after="scrollToItemsOrdered"/> + <!--Create order invoice for first half of ordered items--> + <comment userInput="Admin creates invoice for order" stepKey="adminCreateInvoiceComment" /> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceActionButton"/> + <!--<seeInCurrentUrl url="{{AdminInvoiceNewPage.url}}" stepKey="seeOrderInvoiceUrl" after="clickInvoiceAction"/>--> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage" after="clickInvoiceActionButton"/> + <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced"/> + + <!--Verify items invoiced information--> + + <!--<see selector="{{AdminInvoiceItemsSection.itemQty('1')}}" userInput="Invoiced Partial" stepKey="seeQtyOfItemsInvoiced"/>--> + <fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="invoiceHalfTheItems"/> + + <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQtyToBeInvoiced"/> + <waitForLoadingMaskToDisappear stepKey="WaitForQtyToUpdate"/> + <waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitforSubmitInvoiceBtn"/> + + <!--Submit Invoice--> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="submitInvoice"/> + <waitForLoadingMaskToDisappear stepKey="WaitForInvoiceToSubmit"/> + <!--<waitForElementVisible selector="{{AdminOrderDetailsMessagesSection.successMessage}}" stepKey="waitUntilInvoiceSucesssMsg"/>--> + + <!--Invoice created successfully--> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceSuccessMessage"/> + <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoicesTab"/> + <waitForLoadingMaskToDisappear stepKey="waitForInvoiceGridToLoad" after="clickInvoicesTab"/> + <see selector="{{AdminOrderInvoicesTabSection.gridRow('1')}}" userInput="$665.00" stepKey="seeOrderInvoiceTabInGrid" after="waitForInvoiceGridToLoad"/> + <click selector="{{AdminOrderInvoicesTabSection.viewGridRow('1')}}" stepKey="clickToViewInvoice" after="seeOrderInvoiceTabInGrid"/> + <click selector="{{AdminInvoiceOrderInformationSection.orderId}}" stepKey="clickOrderIdLinkOnInvoice"/> + + <!--Ship Order--> + <comment userInput="Admin creates shipment" stepKey="adminCreatesShipmentComment" before="clickShip"/> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShip" after="clickOrderIdLinkOnInvoice"/> + <seeInCurrentUrl url="{{AdminShipmentNewPage.url}}" stepKey="OrderShipmentUrl" after="clickShip"/> + <scrollTo selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" stepKey="scrollToItemsToShip"/> + <see selector="{{AdminShipmentItemsSection.itemQty('1')}}" userInput="Invoiced 5" stepKey="see5itemsInvoiced"/> + <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="5" stepKey="fillQtyOfItemsToShip"/> + + <!--Submit Shipment--> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="submitShipment" after="fillQtyOfItemsToShip"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="successfullShipmentCreation" after="submitShipment"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="$getOrderId" stepKey="seeOrderIdInPageTitleAfterShip"/> + + <!--Verify Items Status and Shipped Qty in the Items Ordered section--> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToItemsShipped"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 5" stepKey="see5itemsShipped"/> + + <!--Create Credit Memo--> + <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment"/> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreateCreditMemo" after="createCreditMemoComment"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> + + <!--Update Qty of items to be refunded and submit refund--> + <scrollTo selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" stepKey="scrollToItemsToRefund"/> + <fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" stepKey="fillQtyOfItemsToRefund" after="scrollToItemsToRefund"/> + <click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/> + <waitForLoadingMaskToDisappear stepKey="waitForRefundQtyToUpdate"/> + <waitForElementVisible selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="seeSubmitRefundBtn"/> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="submitRefundOffline"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccessMsg" after="submitRefundOffline"/> + + <!--Create invoice for rest of the ordered items--> + <comment userInput="Admin creates invoice for rest of the items" stepKey="adminCreateInvoiceComment2" /> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceActionForRestOfItems"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage2" after="clickInvoiceActionForRestOfItems"/> + + <comment userInput="Qty To Invoice is 5" stepKey="seeRemainderInQtyToInvoice"/> + <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced2"/> + <!--<see selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced2"/>--> + <seeInField userInput="5" selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="see5InTheQtyToInvoice"/> + + <!--Verify items invoiced information--> + <see selector="{{AdminInvoiceItemsSection.itemQty('1')}}" userInput="Refunded 5" stepKey="seeQtyOfItemsRefunded"/> + + <!--Submit Invoice--> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="submitInvoice2" /> + + <!--Invoice created successfully for the rest of the ordered items--> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceSuccessMessage2" after="submitInvoice2"/> + + <!--Verify Ship Action can be done for the rest of the invoiced items --> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipActionForRestOfItems" after="seeInvoiceSuccessMessage2"/> + + <!--Verify Items To Ship section --> + <scrollTo selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" stepKey="scrollToItemsToShip2"/> + <see selector="{{AdminShipmentItemsSection.itemQty('1')}}" userInput="Invoiced 10" stepKey="SeeAll10ItemsInvoiced"/> + <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="5" stepKey="fillRestOfItemsToShip"/> + <!--Submit Shipment--> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="submitShipment2" after="fillRestOfItemsToShip"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="successfullyCreatedShipment" after="submitShipment2"/> + <!--Verify Items Status and Shipped Qty in the Items Ordered section--> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToItemsOrdered2"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 10" stepKey="seeAllItemsShipped"/> </test> </tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml index 562ad729fe7f3..e2191342056ca 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml @@ -12,7 +12,7 @@ <element name="itemName" type="text" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-product .product-title" parameterized="true"/> <element name="itemSku" type="text" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-product .product-sku-block" parameterized="true"/> <element name="itemQty" type="text" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-ordered-qty .qty-table" parameterized="true"/> - <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-qty input.qty-item"/> + <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-qty input.qty-item" parameterized="true"/> <element name="nameColumn" type="text" selector=".order-shipment-table .col-product .product-title"/> <element name="skuColumn" type="text" selector=".order-shipment-table .col-product .product-sku-block"/> </section> From 34f2b469363c9ec1019e1e895f6b49b5b5491586 Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@magento.com> Date: Thu, 28 Jun 2018 15:31:46 -0500 Subject: [PATCH 008/118] MAGETWO-60034: Cannot ship remaining items nan order for several of one product if credit memo is made for some - updated testCaseId --- .../Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index c477fabe04828..2d7fe4d165a59 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -12,7 +12,7 @@ <title value="Email is required to create an order from Admin Panel"/> <description value="Admin should not be able to submit orders without an email address"/> <severity value="MAJOR"/> - <testCaseId value="MAGETWO-60034"/> + <testCaseId value="MAGETWO-93030"/> <group value="sales"/> </annotations> From e52a3265ac0d003ae15f028d14970a5c85528762 Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@magento.com> Date: Thu, 28 Jun 2018 15:49:52 -0500 Subject: [PATCH 009/118] MAGETWO-60034: Cannot ship remaining items nan order for several of one product if credit memo is made for some - updated description title and severity --- .../Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 2d7fe4d165a59..9b629f410f4e4 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -9,9 +9,9 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> <test name="AdminAbleToShipPartiallyInvoicedItemsTest"> <annotations> - <title value="Email is required to create an order from Admin Panel"/> - <description value="Admin should not be able to submit orders without an email address"/> - <severity value="MAJOR"/> + <title value="Ship Action is available for remaining of the partially invoiced items "/> + <description value="Admin should be able to ship remaining ordered items if some of them are already refunded"/> + <severity value="CRITICAL"/> <testCaseId value="MAGETWO-93030"/> <group value="sales"/> @@ -78,10 +78,7 @@ <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced"/> <!--Verify items invoiced information--> - - <!--<see selector="{{AdminInvoiceItemsSection.itemQty('1')}}" userInput="Invoiced Partial" stepKey="seeQtyOfItemsInvoiced"/>--> <fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="invoiceHalfTheItems"/> - <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQtyToBeInvoiced"/> <waitForLoadingMaskToDisappear stepKey="WaitForQtyToUpdate"/> <waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitforSubmitInvoiceBtn"/> From 6421d302bbb8960cc229c3cdbde6b822c8a09538 Mon Sep 17 00:00:00 2001 From: Roman Ganin <rganin@magento.com> Date: Tue, 3 Jul 2018 14:01:28 -0500 Subject: [PATCH 010/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fixing tests for new logic --- .../Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php | 3 ++- .../testsuite/Magento/Sales/Service/V1/RefundOrderTest.php | 5 +++-- .../integration/testsuite/Magento/Paypal/Model/IpnTest.php | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php index 8262a7e41543e..eae0e600434a6 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php @@ -115,7 +115,8 @@ public function testInvoke() ); $this->assertNotEmpty($result); $order = $this->objectManager->get(OrderRepositoryInterface::class)->get($order->getId()); - $this->assertEquals(Order::STATE_CLOSED, $order->getState()); + //Totally refunded orders still can be processed and shipped. + $this->assertEquals(Order::STATE_PROCESSING, $order->getState()); } private function getItemsForRest($order) diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php index 12cbe1ca0e5e2..aacda763ca2aa 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php @@ -86,10 +86,11 @@ public function testShortRequest() 'Failed asserting that proper shipping amount of the Order was refunded' ); - $this->assertNotEquals( + //Totally refunded orders can be processed. + $this->assertEquals( $existingOrder->getStatus(), $updatedOrder->getStatus(), - 'Failed asserting that order status was changed' + 'Failed asserting that order status has not changed' ); } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { $this->fail('Failed asserting that Creditmemo was created'); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php index 1a22ea947f85a..f2cd745e96d83 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php @@ -64,7 +64,8 @@ public function testProcessIpnRequestFullRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); $creditmemo = current($creditmemoItems); - $this->assertEquals(Order::STATE_CLOSED, $order->getState()) ; + //Totally refunded orders still can be shipped + $this->assertEquals(Order::STATE_PROCESSING, $order->getState()) ; $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(Creditmemo::STATE_REFUNDED, $creditmemo->getState()); $this->assertEquals(10, $order->getSubtotalRefunded()); @@ -146,7 +147,8 @@ public function testProcessIpnRequestRestRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); - $this->assertEquals(Order::STATE_CLOSED, $order->getState()) ; + //Totally refunded orders still can be shipped + $this->assertEquals(Order::STATE_PROCESSING, $order->getState()) ; $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(10, $order->getSubtotalRefunded()); $this->assertEquals(10, $order->getBaseSubtotalRefunded()); From 9864ab822f453e0a4fe0e20bda28d5cfe26cbc36 Mon Sep 17 00:00:00 2001 From: Roman Ganin <rganin@magento.com> Date: Tue, 3 Jul 2018 14:33:08 -0500 Subject: [PATCH 011/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fixed test --- .../app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml index d4b9856c5e319..e6ab0ff5026b6 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml @@ -22,7 +22,7 @@ <data name="steps" xsi:type="string">invoice, shipment|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Complete,Closed</data> + <data name="resultStatuses" xsi:type="string">Complete,Processing</data> <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> From bd8a83b8308963fb19e9938f09f2b4962982c80f Mon Sep 17 00:00:00 2001 From: Roman Ganin <rganin@magento.com> Date: Thu, 12 Jul 2018 14:50:12 -0500 Subject: [PATCH 012/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some --- app/code/Magento/Sales/Model/Order.php | 8 +- .../Sales/Test/Unit/Model/OrderTest.php | 161 +++++++++++++++++- 2 files changed, 167 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index d3b8edbed2eea..7f44e286fb8ce 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -546,7 +546,13 @@ public function canCancel() break; } } - if ($allInvoiced) { + + $allRefunded = true; + foreach ($this->getAllItems() as $orderItem) { + $allRefunded = $allRefunded && ((float)$orderItem->getQtyRefunded() == (float)$orderItem->getQtyInvoiced()); + } + + if ($allInvoiced && !$allRefunded) { return false; } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 7f6363346872c..b4b42d0da2d69 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -114,7 +114,9 @@ protected function setUp() 'getParentItemId', 'getQuoteItemId', 'getLockedDoInvoice', - 'getProductId' + 'getProductId', + 'getQtyRefunded', + 'getQtyInvoiced', ]); $this->salesOrderCollectionMock = $this->getMockBuilder( \Magento\Sales\Model\ResourceModel\Order\Collection::class @@ -619,6 +621,163 @@ public function testCanCancelAllInvoiced() $this->item->expects($this->any()) ->method('getQtyToInvoice') ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(1); + + $this->assertFalse($this->order->canCancel()); + } + + public function testCanCancelAllRefunded() + { + $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class) + ->disableOriginalConstructor() + ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp']) + ->getMock(); + $paymentMock->expects($this->any()) + ->method('canReviewPayment') + ->will($this->returnValue(false)); + $paymentMock->expects($this->any()) + ->method('canFetchTransactionInfo') + ->will($this->returnValue(false)); + $collectionMock = $this->createPartialMock( + \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, + ['getItems', 'setOrderFilter'] + ); + $this->orderItemCollectionFactoryMock->expects($this->any()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->any()) + ->method('setOrderFilter') + ->willReturnSelf(); + $this->preparePaymentMock($paymentMock); + + $this->prepareItemMock(0); + + $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); + $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); + + $this->item->expects($this->any()) + ->method('isDeleted') + ->willReturn(false); + $this->item->expects($this->any()) + ->method('getQtyToInvoice') + ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(10); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(10); + + $this->assertTrue($this->order->canCancel()); + } + + /** + * Test that order can be canceled if some items were partially invoiced with certain qty + * and then refunded for this qty. + * Sample: + * - ordered qty = 20 + * - invoiced = 10 + * - refunded = 10 + */ + public function testCanCancelPartiallyInvoicedAndRefunded() + { + $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class) + ->disableOriginalConstructor() + ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp']) + ->getMock(); + $paymentMock->expects($this->any()) + ->method('canReviewPayment') + ->will($this->returnValue(false)); + $paymentMock->expects($this->any()) + ->method('canFetchTransactionInfo') + ->will($this->returnValue(false)); + $collectionMock = $this->createPartialMock( + \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, + ['getItems', 'setOrderFilter'] + ); + $this->orderItemCollectionFactoryMock->expects($this->any()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->any()) + ->method('setOrderFilter') + ->willReturnSelf(); + $this->preparePaymentMock($paymentMock); + + $this->prepareItemMock(0); + + $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); + $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); + + $this->item->expects($this->any()) + ->method('isDeleted') + ->willReturn(false); + $this->item->expects($this->any()) + ->method('getQtyToInvoice') + ->willReturn(10); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(10); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(10); + + $this->assertTrue($this->order->canCancel()); + } + + /** + * Test that order CAN NOT be canceled if some items were partially invoiced with certain qty + * and then refunded for less than that qty. + * Sample: + * - ordered qty = 10 + * - invoiced = 10 + * - refunded = 5 + */ + public function testCanCancelPartiallyInvoicedAndNotFullyRefunded() + { + $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class) + ->disableOriginalConstructor() + ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp']) + ->getMock(); + $paymentMock->expects($this->any()) + ->method('canReviewPayment') + ->will($this->returnValue(false)); + $paymentMock->expects($this->any()) + ->method('canFetchTransactionInfo') + ->will($this->returnValue(false)); + $collectionMock = $this->createPartialMock( + \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, + ['getItems', 'setOrderFilter'] + ); + $this->orderItemCollectionFactoryMock->expects($this->any()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->any()) + ->method('setOrderFilter') + ->willReturnSelf(); + $this->preparePaymentMock($paymentMock); + + $this->prepareItemMock(0); + + $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); + $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); + + $this->item->expects($this->any()) + ->method('isDeleted') + ->willReturn(false); + $this->item->expects($this->any()) + ->method('getQtyToInvoice') + ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(5); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(10); $this->assertFalse($this->order->canCancel()); } From 0a46c8aeeb0b69615f44bb543e6731d264523104 Mon Sep 17 00:00:00 2001 From: Roman Ganin <rganin@magento.com> Date: Thu, 12 Jul 2018 17:04:29 -0500 Subject: [PATCH 013/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some --- app/code/Magento/Sales/Test/Unit/Model/OrderTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index b4b42d0da2d69..b75e3adb7402b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -17,6 +17,7 @@ * Test class for \Magento\Sales\Model\Order * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ class OrderTest extends \PHPUnit\Framework\TestCase { From 7bf456a3eb8e0072ef1e6b22467a75f48336a606 Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar <mbalidar@comwrap.com> Date: Wed, 29 Aug 2018 09:54:22 +0200 Subject: [PATCH 014/118] add user type for asynchronous operations --- .../Api/Data/BulkSummaryInterface.php | 17 +++++++++++++++++ .../Model/BulkManagement.php | 10 ++++++++++ .../Model/BulkSummary.php | 16 ++++++++++++++++ .../Test/Unit/Model/BulkManagementTest.php | 2 ++ .../AsynchronousOperations/etc/db_schema.xml | 1 + .../AsynchronousOperations/_files/bulk.php | 9 +++++++-- 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php index f5dd5bb13eabb..435cf5e433baa 100644 --- a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php +++ b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php @@ -13,6 +13,8 @@ */ interface BulkSummaryInterface extends \Magento\Framework\Bulk\BulkSummaryInterface { + const USER_TYPE = 'user_type'; + /** * Retrieve existing extension attributes object. * @@ -31,4 +33,19 @@ public function getExtensionAttributes(); public function setExtensionAttributes( \Magento\AsynchronousOperations\Api\Data\BulkSummaryExtensionInterface $extensionAttributes ); + + /** + * Get user type + * + * @return int + */ + public function getUserType(); + + /** + * Set user type + * @param int $operationCount + * @return $this + */ + public function setUserType($userType); + } diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php index 4f086ce8ac2ca..add7d220e8efb 100644 --- a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php +++ b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php @@ -13,6 +13,7 @@ use Magento\Framework\EntityManager\EntityManager; use Magento\Framework\EntityManager\MetadataPool; use Magento\AsynchronousOperations\Model\ResourceModel\Operation\CollectionFactory; +use Magento\Authorization\Model\UserContextInterface; /** * Class BulkManagement @@ -51,6 +52,11 @@ class BulkManagement implements \Magento\Framework\Bulk\BulkManagementInterface */ private $resourceConnection; + /** + * @var \Magento\Authorization\Model\UserContextInterface + */ + private $userContext; + /** * @var \Psr\Log\LoggerInterface */ @@ -73,6 +79,7 @@ public function __construct( BulkPublisherInterface $publisher, MetadataPool $metadataPool, ResourceConnection $resourceConnection, + UserContextInterface $userContext, \Psr\Log\LoggerInterface $logger ) { $this->entityManager = $entityManager; @@ -81,6 +88,7 @@ public function __construct( $this->metadataPool = $metadataPool; $this->resourceConnection = $resourceConnection; $this->publisher = $publisher; + $this->userContext = $userContext; $this->logger = $logger; } @@ -93,6 +101,7 @@ public function scheduleBulk($bulkUuid, array $operations, $description, $userId $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); // save bulk summary and related operations $connection->beginTransaction(); + $userType = $this->userContext->getUserType(); try { /** @var \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface $bulkSummary */ $bulkSummary = $this->bulkSummaryFactory->create(); @@ -100,6 +109,7 @@ public function scheduleBulk($bulkUuid, array $operations, $description, $userId $bulkSummary->setBulkId($bulkUuid); $bulkSummary->setDescription($description); $bulkSummary->setUserId($userId); + $bulkSummary->setUserType($userType); $bulkSummary->setOperationCount((int)$bulkSummary->getOperationCount() + count($operations)); $this->entityManager->save($bulkSummary); diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php b/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php index e99233d076957..1d834ad10b2e7 100644 --- a/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php +++ b/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php @@ -78,6 +78,22 @@ public function setUserId($userId) return $this->setData(self::USER_ID, $userId); } + /** + * @inheritDoc + */ + public function getUserType() + { + return $this->getData(self::USER_TYPE); + } + + /** + * @inheritDoc + */ + public function setUserType($userType) + { + return $this->setData(self::USER_TYPE, $userType); + } + /** * @inheritDoc */ diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php index 3a45c34df17f8..e9fabb6150d6c 100644 --- a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php @@ -108,6 +108,7 @@ public function testScheduleBulk() $bulkUuid = 'bulk-001'; $description = 'Bulk summary description...'; $userId = 1; + $userType = 2; $connectionName = 'default'; $topicNames = ['topic.name.0', 'topic.name.1']; $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) @@ -131,6 +132,7 @@ public function testScheduleBulk() $bulkSummary->expects($this->once())->method('setBulkId')->with($bulkUuid)->willReturnSelf(); $bulkSummary->expects($this->once())->method('setDescription')->with($description)->willReturnSelf(); $bulkSummary->expects($this->once())->method('setUserId')->with($userId)->willReturnSelf(); + $bulkSummary->expects($this->once())->method('getUserType')->with($userType)->willReturnSelf(); $bulkSummary->expects($this->once())->method('getOperationCount')->willReturn(1); $bulkSummary->expects($this->once())->method('setOperationCount')->with(3)->willReturnSelf(); $this->entityManager->expects($this->once())->method('save')->with($bulkSummary)->willReturn($bulkSummary); diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml index a3acb7897580f..c8e733a7956ec 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml @@ -15,6 +15,7 @@ comment="Bulk UUID (can be exposed to reference bulk entity)"/> <column xsi:type="int" name="user_id" padding="10" unsigned="true" nullable="true" identity="false" comment="ID of the WebAPI user that performed an action"/> + <column xsi:type="int" name="user_type" nullable="false" comment="Which type of user"/> <column xsi:type="varchar" name="description" nullable="true" length="255" comment="Bulk Description"/> <column xsi:type="int" name="operation_count" padding="10" unsigned="true" nullable="false" identity="false" comment="Total number of operations scheduled within this bulk"/> diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php index 787d2c10a44c4..0c10796a30ef2 100644 --- a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php @@ -18,30 +18,35 @@ 'not_started' => [ 'uuid' => 'bulk-uuid-1', 'user_id' => 1, + 'user_type' => 2, 'description' => 'Bulk Description', 'operation_count' => 1, ], 'in_progress_success' => [ 'uuid' => 'bulk-uuid-2', 'user_id' => 1, + 'user_type' => 2, 'description' => 'Bulk Description', 'operation_count' => 3, ], 'in_progress_failed' => [ 'uuid' => 'bulk-uuid-3', 'user_id' => 1, + 'user_type' => 2, 'description' => 'Bulk Description', 'operation_count' => 2, ], 'finish_success' => [ 'uuid' => 'bulk-uuid-4', 'user_id' => 1, + 'user_type' => 2, 'description' => 'Bulk Description', 'operation_count' => 1, ], 'finish_failed' => [ 'uuid' => 'bulk-uuid-5', 'user_id' => 1, + 'user_type' => 2, 'description' => 'Bulk Description', 'operation_count' => 2, ] @@ -91,8 +96,8 @@ ]; -$bulkQuery = "INSERT INTO {$bulkTable} (`uuid`, `user_id`, `description`, `operation_count`)" - . " VALUES (:uuid, :user_id, :description, :operation_count);"; +$bulkQuery = "INSERT INTO {$bulkTable} (`uuid`, `user_id`, `user_type`, `description`, `operation_count`)" + . " VALUES (:uuid, :user_id, :user_type, :description, :operation_count);"; foreach ($bulks as $bulk) { $connection->query($bulkQuery, $bulk); } From 9d112a661e0b892f8d89d6b4d5e65af3f2315ef5 Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar <mbalidar@comwrap.com> Date: Thu, 30 Aug 2018 13:31:11 +0200 Subject: [PATCH 015/118] add user type of bulk operation --- app/code/Magento/AsynchronousOperations/etc/db_schema.xml | 2 +- .../Magento/AsynchronousOperations/etc/db_schema_whitelist.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml index c8e733a7956ec..94ee5a16b5b84 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml @@ -15,7 +15,7 @@ comment="Bulk UUID (can be exposed to reference bulk entity)"/> <column xsi:type="int" name="user_id" padding="10" unsigned="true" nullable="true" identity="false" comment="ID of the WebAPI user that performed an action"/> - <column xsi:type="int" name="user_type" nullable="false" comment="Which type of user"/> + <column xsi:type="int" name="user_type" nullable="true" comment="Which type of user"/> <column xsi:type="varchar" name="description" nullable="true" length="255" comment="Bulk Description"/> <column xsi:type="int" name="operation_count" padding="10" unsigned="true" nullable="false" identity="false" comment="Total number of operations scheduled within this bulk"/> diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json index 6b18ac3e29d43..365c8d5b9b0b1 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json @@ -4,6 +4,7 @@ "id": true, "uuid": true, "user_id": true, + "user_type": true, "description": true, "operation_count": true, "start_time": true From 97242021d4fffa02ca7d8e48710a9343f41316d4 Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar <mbalidar@comwrap.com> Date: Fri, 31 Aug 2018 16:08:50 +0200 Subject: [PATCH 016/118] remove empty line from interface --- .../AsynchronousOperations/Api/Data/BulkSummaryInterface.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php index 435cf5e433baa..4b65f2a207b75 100644 --- a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php +++ b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php @@ -47,5 +47,4 @@ public function getUserType(); * @return $this */ public function setUserType($userType); - } From 73d1e388e9df3945c6410b991da8227b4893c061 Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar <mbalidar@comwrap.com> Date: Wed, 5 Sep 2018 11:48:29 +0200 Subject: [PATCH 017/118] add user type for asynchronous operations --- .../Api/Data/BulkSummaryInterface.php | 2 +- .../AsynchronousOperations/Model/BulkManagement.php | 3 +++ .../Test/Unit/Model/BulkManagementTest.php | 4 ++-- .../Magento/AsynchronousOperations/_files/bulk.php | 10 +++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php index 4b65f2a207b75..9593cb983950a 100644 --- a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php +++ b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php @@ -43,7 +43,7 @@ public function getUserType(); /** * Set user type - * @param int $operationCount + * @param int $userType * @return $this */ public function setUserType($userType); diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php index add7d220e8efb..169c59aa1c749 100644 --- a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php +++ b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php @@ -102,6 +102,9 @@ public function scheduleBulk($bulkUuid, array $operations, $description, $userId // save bulk summary and related operations $connection->beginTransaction(); $userType = $this->userContext->getUserType(); + if (is_null($userType)) { + $userType = UserContextInterface::USER_TYPE_ADMIN; + } try { /** @var \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface $bulkSummary */ $bulkSummary = $this->bulkSummaryFactory->create(); diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php index e9fabb6150d6c..e5951fb129e7e 100644 --- a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php @@ -108,7 +108,7 @@ public function testScheduleBulk() $bulkUuid = 'bulk-001'; $description = 'Bulk summary description...'; $userId = 1; - $userType = 2; + $userType = \Magento\Authorization\Model\UserContextInterface::USER_TYPE_ADMIN; $connectionName = 'default'; $topicNames = ['topic.name.0', 'topic.name.1']; $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) @@ -132,7 +132,7 @@ public function testScheduleBulk() $bulkSummary->expects($this->once())->method('setBulkId')->with($bulkUuid)->willReturnSelf(); $bulkSummary->expects($this->once())->method('setDescription')->with($description)->willReturnSelf(); $bulkSummary->expects($this->once())->method('setUserId')->with($userId)->willReturnSelf(); - $bulkSummary->expects($this->once())->method('getUserType')->with($userType)->willReturnSelf(); + $bulkSummary->expects($this->once())->method('setUserType')->with($userType)->willReturnSelf(); $bulkSummary->expects($this->once())->method('getOperationCount')->willReturn(1); $bulkSummary->expects($this->once())->method('setOperationCount')->with(3)->willReturnSelf(); $this->entityManager->expects($this->once())->method('save')->with($bulkSummary)->willReturn($bulkSummary); diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php index d5de12a3503b7..9e215667903d3 100644 --- a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php @@ -18,35 +18,35 @@ 'not_started' => [ 'uuid' => 'bulk-uuid-1', 'user_id' => 1, - 'user_type' => 2, + 'user_type' => \Magento\Authorization\Model\UserContextInterface::USER_TYPE_ADMIN, 'description' => 'Bulk Description', 'operation_count' => 1, ], 'in_progress_success' => [ 'uuid' => 'bulk-uuid-2', 'user_id' => 1, - 'user_type' => 2, + 'user_type' => \Magento\Authorization\Model\UserContextInterface::USER_TYPE_ADMIN, 'description' => 'Bulk Description', 'operation_count' => 3, ], 'in_progress_failed' => [ 'uuid' => 'bulk-uuid-3', 'user_id' => 1, - 'user_type' => 2, + 'user_type' => \Magento\Authorization\Model\UserContextInterface::USER_TYPE_ADMIN, 'description' => 'Bulk Description', 'operation_count' => 2, ], 'finish_success' => [ 'uuid' => 'bulk-uuid-4', 'user_id' => 1, - 'user_type' => 2, + 'user_type' => \Magento\Authorization\Model\UserContextInterface::USER_TYPE_ADMIN, 'description' => 'Bulk Description', 'operation_count' => 1, ], 'finish_failed' => [ 'uuid' => 'bulk-uuid-5', 'user_id' => 1, - 'user_type' => 2, + 'user_type' => \Magento\Authorization\Model\UserContextInterface::USER_TYPE_ADMIN, 'description' => 'Bulk Description', 'operation_count' => 2, ], From 614ed8af527c004041d7c504f1df3934a10a19b0 Mon Sep 17 00:00:00 2001 From: Munkh-Ulzii Balidar <mbalidar@comwrap.com> Date: Wed, 5 Sep 2018 16:47:43 +0200 Subject: [PATCH 018/118] remove redundant dependency --- .../Magento/AsynchronousOperations/Model/BulkManagement.php | 2 +- app/code/Magento/AsynchronousOperations/composer.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php index 169c59aa1c749..1d7d15f84163f 100644 --- a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php +++ b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php @@ -102,7 +102,7 @@ public function scheduleBulk($bulkUuid, array $operations, $description, $userId // save bulk summary and related operations $connection->beginTransaction(); $userType = $this->userContext->getUserType(); - if (is_null($userType)) { + if ($userType === null) { $userType = UserContextInterface::USER_TYPE_ADMIN; } try { diff --git a/app/code/Magento/AsynchronousOperations/composer.json b/app/code/Magento/AsynchronousOperations/composer.json index 7d5a097eeea3f..18927b5f4ecca 100644 --- a/app/code/Magento/AsynchronousOperations/composer.json +++ b/app/code/Magento/AsynchronousOperations/composer.json @@ -10,7 +10,6 @@ "magento/module-authorization": "*", "magento/module-backend": "*", "magento/module-ui": "*", - "magento/module-user": "*", "php": "~7.1.3||~7.2.0" }, "suggest": { From a5b048f9cb84867f5104d288223605f85378e3c9 Mon Sep 17 00:00:00 2001 From: Devagouda Patil <depatil@Devagoudas-MacBook-Pro.local> Date: Wed, 5 Sep 2018 17:24:21 -0500 Subject: [PATCH 019/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - Updated Functional test path and schema location --- .../Mftf}/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename {dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales => app/code/Magento/Sales/Test/Mftf}/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml (98%) diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml similarity index 98% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml rename to app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 9b629f410f4e4..3fdbb3eae0b19 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -6,7 +6,7 @@ */ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AdminAbleToShipPartiallyInvoicedItemsTest"> <annotations> <title value="Ship Action is available for remaining of the partially invoiced items "/> @@ -64,6 +64,7 @@ <!--Submit Order and verify information--> <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder" after="seeCorrectGrandTotal"/> + <waitForPageLoad stepKey="waitForOrderToProcess"/> <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPage" after="clickSubmitOrder"/> <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeSuccessMessage" after="seeViewOrderPage"/> <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId" after="seeSuccessMessage"/> From df6bc3769f1d5b6c2afc394586aa21113d915d1f Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Thu, 6 Sep 2018 17:11:24 -0500 Subject: [PATCH 020/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Catalog/view/adminhtml/web/js/options.js | 12 ++++++-- .../adminhtml/web/js/product-attributes.js | 29 ++++++++++++------- lib/web/mage/backend/validation.js | 2 ++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js index 6ea005915763c..a4b3ca95e45da 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js @@ -145,7 +145,9 @@ define([ return optionDefaultInputType; } - }; + }, + formContent = jQuery(), + optionTable = optionPanel.find('table'); if ($('add_new_option_button')) { Event.observe('add_new_option_button', 'click', attributeOption.add.bind(attributeOption, {}, true)); @@ -180,7 +182,7 @@ define([ }); }); } - editForm.on('submit', function () { + editForm.on('beforeSubmit', function () { optionPanel.find('input') .each(function () { if (this.disabled) { @@ -202,9 +204,13 @@ define([ }) .val(JSON.stringify(optionsValues)) .prependTo(editForm); - optionPanel.find('table') + formContent = optionTable.clone(true); + optionTable .replaceWith(jQuery('<div>').text(jQuery.mage.__('Sending attribute values as package.'))); }); + editForm.on('afterValidate.error', function () { + optionTable.replaceWith(formContent); + }); window.attributeOption = attributeOption; window.optionDefaultInputType = attributeOption.getOptionInputType(); diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index 01411523108cf..870d1dedefede 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -414,7 +414,15 @@ define([ }; $(function () { - var editForm = $('#edit_form'); + var editForm = $('#edit_form'), + swatchVisualPanel = $('#swatch-visual-options-panel'), + swatchTextPanel = $('#swatch-text-options-panel'), + activePanel, + formContent = $(), + optionTable; + + activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel; + optionTable = activePanel.find('table'); $('#frontend_input').bind('change', function () { swatchProductAttributes.bindAttributeInputType(); @@ -430,16 +438,11 @@ define([ .collapsable() .collapse('hide'); - editForm.on('submit', function () { - var activePanel, - swatchValues = [], - swatchVisualPanel = $('#swatch-visual-options-panel'), - swatchTextPanel = $('#swatch-text-options-panel'); - - activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel; + editForm.on('beforeSubmit', function () { + var swatchValues = []; - activePanel - .find('table input') + optionTable + .find('input') .each(function () { swatchValues.push(this.name + '=' + $(this).val()); }); @@ -452,11 +455,17 @@ define([ .val(JSON.stringify(swatchValues)) .prependTo(editForm); + formContent = optionTable.clone(true); + [swatchVisualPanel, swatchTextPanel].forEach(function (el) { $(el).find('table') .replaceWith($('<div>').text($.mage.__('Sending swatch values as package.'))); }); }); + + editForm.on('afterValidate.error', function () { + optionTable.replaceWith(formContent); + }); }); window.saveAttributeInNewSet = swatchProductAttributes.saveAttributeInNewSet; diff --git a/lib/web/mage/backend/validation.js b/lib/web/mage/backend/validation.js index d3ab7dd086a43..1043f45a7402e 100644 --- a/lib/web/mage/backend/validation.js +++ b/lib/web/mage/backend/validation.js @@ -171,6 +171,7 @@ this._submit(); } else { this._showErrors(response); + $(this.element[0]).trigger('afterValidate.error'); $('body').trigger('processStop'); } }, @@ -223,6 +224,7 @@ * @protected */ _onError: function () { + $(this.element[0]).trigger('afterValidate.error'); $('body').trigger('processStop'); if (this.options.errorUrl) { From de672221506c6ec7ce506e6499ac9ab16d69acf3 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Fri, 7 Sep 2018 17:06:23 -0500 Subject: [PATCH 021/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Adminhtml/Product/Attribute/Save.php | 36 +++++++++---- .../Adminhtml/Product/Attribute/Validate.php | 27 ++++++++-- .../Attribute/Option/OptionsDataProvider.php | 39 +++++++++++++++ .../Catalog/view/adminhtml/web/js/options.js | 50 ++++++++++--------- .../Product/Attribute/Plugin/Save.php | 9 ---- 5 files changed, 115 insertions(+), 46 deletions(-) create mode 100644 app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 817de6828e48d..a7076ba8526fe 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -13,6 +13,7 @@ use Magento\Catalog\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Helper\Product; use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataProvider; use Magento\Catalog\Model\Product\AttributeSet\BuildFactory; use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory; use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator; @@ -75,6 +76,11 @@ class Save extends Attribute */ private $presentation; + /** + * @var OptionsDataProvider|null + */ + private $optionsDataProvider; + /** * @param Context $context * @param FrontendInterface $attributeLabelCache @@ -88,6 +94,7 @@ class Save extends Attribute * @param Product $productHelper * @param LayoutFactory $layoutFactory * @param Presentation|null $presentation + * @param OptionsDataProvider|null $optionsDataProvider * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -102,7 +109,8 @@ public function __construct( FilterManager $filterManager, Product $productHelper, LayoutFactory $layoutFactory, - Presentation $presentation = null + Presentation $presentation = null, + OptionsDataProvider $optionsDataProvider = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->buildFactory = $buildFactory; @@ -113,6 +121,8 @@ public function __construct( $this->groupCollectionFactory = $groupCollectionFactory; $this->layoutFactory = $layoutFactory; $this->presentation = $presentation ?: ObjectManager::getInstance()->get(Presentation::class); + $this->optionsDataProvider = $optionsDataProvider + ?: ObjectManager::getInstance()->get(OptionsDataProvider::class); } /** @@ -123,7 +133,21 @@ public function __construct( */ public function execute() { + try { + $optionData = $this->optionsDataProvider->getOptionsData($this->getRequest()); + } catch (\InvalidArgumentException $e) { + $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " + . "If the error persists, please try again later."); + $this->messageManager->addErrorMessage($message); + return $this->returnResult('catalog/*/edit', ['_current' => true], ['error' => true]); + } + $data = $this->getRequest()->getPostValue(); + $data = array_merge_recursive( + $data, + $optionData + ); + if ($data) { $this->preprocessOptionsData($data); $setId = $this->getRequest()->getParam('set'); @@ -326,15 +350,7 @@ public function execute() */ private function preprocessOptionsData(&$data) { - if (isset($data['serialized_options'])) { - $serializedOptions = json_decode($data['serialized_options'], JSON_OBJECT_AS_ARRAY); - foreach ($serializedOptions as $serializedOption) { - $option = []; - parse_str($serializedOption, $option); - $data = array_replace_recursive($data, $option); - } - } - unset($data['serialized_options']); + } /** diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index db452113ada06..35cc2a903bc96 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -7,6 +7,8 @@ namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataProvider; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute @@ -28,6 +30,11 @@ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute */ private $multipleAttributeList; + /** + * @var OptionsDataProvider|null + */ + private $optionsDataProvider; + /** * Constructor * @@ -38,6 +45,7 @@ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\View\LayoutFactory $layoutFactory * @param array $multipleAttributeList + * @param OptionsDataProvider|null $optionsDataProvider */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -46,12 +54,15 @@ public function __construct( \Magento\Framework\View\Result\PageFactory $resultPageFactory, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, \Magento\Framework\View\LayoutFactory $layoutFactory, - array $multipleAttributeList = [] + array $multipleAttributeList = [], + OptionsDataProvider $optionsDataProvider = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; $this->multipleAttributeList = $multipleAttributeList; + $this->optionsDataProvider = $optionsDataProvider ?: ObjectManager::getInstance() + ->get(OptionsDataProvider::class); } /** @@ -63,6 +74,14 @@ public function execute() { $response = new DataObject(); $response->setError(false); + try { + $optionsData = $this->optionsDataProvider->getOptionsData($this->getRequest()); + } catch (\InvalidArgumentException $e) { + $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " + . "If the error persists, please try again later."); + $this->setMessageToResponse($response, [$message]); + $response->setError(true); + } $attributeCode = $this->getRequest()->getParam('attribute_code'); $frontendLabel = $this->getRequest()->getParam('frontend_label'); @@ -102,10 +121,10 @@ public function execute() } $multipleOption = $this->getRequest()->getParam("frontend_input"); - $multipleOption = null == $multipleOption ? 'select' : $multipleOption; + $multipleOption = (null === $multipleOption) ? 'select' : $multipleOption; - if (isset($this->multipleAttributeList[$multipleOption]) && !(null == ($multipleOption))) { - $options = $this->getRequest()->getParam($this->multipleAttributeList[$multipleOption]); + if (isset($this->multipleAttributeList[$multipleOption])) { + $options = $optionsData[$this->multipleAttributeList[$multipleOption]] ?? null; $this->checkUniqueOption( $response, $options diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php new file mode 100644 index 0000000000000..a2a1fcb7fb526 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Model\Product\Attribute\Option; + +use Magento\Framework\App\RequestInterface; + +class OptionsDataProvider +{ + /** + * @param RequestInterface $request + * @return array + * @throws \InvalidArgumentException + */ + public function getOptionsData(RequestInterface $request): array + { + $serializedOptions = $request->getParam('serialized_options'); + $optionsData = []; + + if ($serializedOptions) { + $encodedOptions = json_decode($serializedOptions, JSON_OBJECT_AS_ARRAY); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \InvalidArgumentException('Unable to unserialize options data.'); + } + + foreach ($encodedOptions as $encodedOption) { + $decodedOptionData = []; + parse_str($encodedOption, $decodedOptionData); + $optionsData = array_replace_recursive($optionsData, $decodedOptionData); + } + } + + return $optionsData; + } +} \ No newline at end of file diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js index a4b3ca95e45da..233f554512f8c 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js @@ -146,8 +146,8 @@ define([ return optionDefaultInputType; } }, - formContent = jQuery(), - optionTable = optionPanel.find('table'); + optionsTableContent = jQuery(), + optionContainer = optionPanel.find('table tbody'); if ($('add_new_option_button')) { Event.observe('add_new_option_button', 'click', attributeOption.add.bind(attributeOption, {}, true)); @@ -183,33 +183,37 @@ define([ }); } editForm.on('beforeSubmit', function () { - optionPanel.find('input') - .each(function () { - if (this.disabled) { - return; - } + if (optionPanel.is(':visible')) { + optionContainer.find('input') + .each(function () { + if (this.disabled) { + return; + } - if (this.type === 'checkbox' || this.type === 'radio') { - if (this.checked) { + if (this.type === 'checkbox' || this.type === 'radio') { + if (this.checked) { + optionsValues.push(this.name + '=' + jQuery(this).val()); + } + } else { optionsValues.push(this.name + '=' + jQuery(this).val()); } - } else { - optionsValues.push(this.name + '=' + jQuery(this).val()); - } - }); - jQuery('<input>') - .attr({ - type: 'hidden', - name: 'serialized_options' - }) - .val(JSON.stringify(optionsValues)) - .prependTo(editForm); - formContent = optionTable.clone(true); - optionTable + }); + jQuery('<input>') + .attr({ + type: 'hidden', + name: 'serialized_options' + }) + .val(JSON.stringify(optionsValues)) + .prependTo(editForm); + } + optionsTableContent = optionContainer.clone(true); + optionContainer .replaceWith(jQuery('<div>').text(jQuery.mage.__('Sending attribute values as package.'))); }); editForm.on('afterValidate.error', function () { - optionTable.replaceWith(formContent); + if (optionPanel.is(':visible')) { + optionContainer.replaceWith(optionsTableContent); + } }); window.attributeOption = attributeOption; window.optionDefaultInputType = attributeOption.getOptionInputType(); diff --git a/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php b/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php index 383c97a166d34..9ec65fb08045c 100644 --- a/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php +++ b/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php @@ -26,15 +26,6 @@ public function beforeDispatch(Attribute\Save $subject, RequestInterface $reques $data = $request->getPostValue(); if (isset($data['frontend_input'])) { - //Data is serialized to overcome issues caused by max_input_vars value if it's modification is unavailable. - //See subject controller code and comments for more info. - if (isset($data['serialized_swatch_values']) - && in_array($data['frontend_input'], ['swatch_visual', 'swatch_text']) - ) { - $data['serialized_options'] = $data['serialized_swatch_values']; - unset($data['serialized_swatch_values']); - } - switch ($data['frontend_input']) { case 'swatch_visual': $data[Swatch::SWATCH_INPUT_TYPE_KEY] = Swatch::SWATCH_INPUT_TYPE_VISUAL; From 8ec2c30e99f70a7ba78602f51476c38625200f1e Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Sun, 9 Sep 2018 19:34:52 -0500 Subject: [PATCH 022/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../adminhtml/web/js/product-attributes.js | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index 870d1dedefede..dd1fb4b0a8b54 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -417,12 +417,9 @@ define([ var editForm = $('#edit_form'), swatchVisualPanel = $('#swatch-visual-options-panel'), swatchTextPanel = $('#swatch-text-options-panel'), - activePanel, - formContent = $(), - optionTable; - - activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel; - optionTable = activePanel.find('table'); + optionsTableContent = $(), + optionContainer = $(), + activePanel = $(); $('#frontend_input').bind('change', function () { swatchProductAttributes.bindAttributeInputType(); @@ -441,22 +438,26 @@ define([ editForm.on('beforeSubmit', function () { var swatchValues = []; - optionTable - .find('input') - .each(function () { - swatchValues.push(this.name + '=' + $(this).val()); - }); + activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel; + optionContainer = activePanel.find('table tbody'); - $('<input>') - .attr({ - type: 'hidden', - name: 'serialized_swatch_values' - }) - .val(JSON.stringify(swatchValues)) - .prependTo(editForm); + if (activePanel.is(':visible')) { + optionContainer + .find('input') + .each(function () { + swatchValues.push(this.name + '=' + $(this).val()); + }); - formContent = optionTable.clone(true); + $('<input>') + .attr({ + type: 'hidden', + name: 'serialized_options' + }) + .val(JSON.stringify(swatchValues)) + .prependTo(editForm); + } + optionsTableContent = optionContainer.clone(true); [swatchVisualPanel, swatchTextPanel].forEach(function (el) { $(el).find('table') .replaceWith($('<div>').text($.mage.__('Sending swatch values as package.'))); @@ -464,7 +465,9 @@ define([ }); editForm.on('afterValidate.error', function () { - optionTable.replaceWith(formContent); + if (activePanel.is(':visible')) { + optionContainer.replaceWith(optionsTableContent); + } }); }); From 616eb6d5a9f0ac88730c8db38b40d151f64e94f4 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 10 Sep 2018 13:20:09 -0500 Subject: [PATCH 023/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Adminhtml/Product/Attribute/Save.php | 31 +++++-------------- .../Adminhtml/Product/Attribute/Validate.php | 18 +++++------ ...taProvider.php => OptionsDataResolver.php} | 9 ++++-- .../Catalog/view/adminhtml/web/js/options.js | 14 ++++----- .../adminhtml/web/js/product-attributes.js | 15 ++++----- 5 files changed, 37 insertions(+), 50 deletions(-) rename app/code/Magento/Catalog/Model/Product/Attribute/Option/{OptionsDataProvider.php => OptionsDataResolver.php} (88%) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index a7076ba8526fe..825288b366410 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -13,7 +13,7 @@ use Magento\Catalog\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Helper\Product; use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataProvider; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataResolver; use Magento\Catalog\Model\Product\AttributeSet\BuildFactory; use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory; use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator; @@ -77,9 +77,9 @@ class Save extends Attribute private $presentation; /** - * @var OptionsDataProvider|null + * @var OptionsDataResolver|null */ - private $optionsDataProvider; + private $optionsDataResolver; /** * @param Context $context @@ -94,7 +94,7 @@ class Save extends Attribute * @param Product $productHelper * @param LayoutFactory $layoutFactory * @param Presentation|null $presentation - * @param OptionsDataProvider|null $optionsDataProvider + * @param OptionsDataResolver|null $optionsDataResolver * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -110,7 +110,7 @@ public function __construct( Product $productHelper, LayoutFactory $layoutFactory, Presentation $presentation = null, - OptionsDataProvider $optionsDataProvider = null + OptionsDataResolver $optionsDataResolver = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->buildFactory = $buildFactory; @@ -121,8 +121,8 @@ public function __construct( $this->groupCollectionFactory = $groupCollectionFactory; $this->layoutFactory = $layoutFactory; $this->presentation = $presentation ?: ObjectManager::getInstance()->get(Presentation::class); - $this->optionsDataProvider = $optionsDataProvider - ?: ObjectManager::getInstance()->get(OptionsDataProvider::class); + $this->optionsDataResolver = $optionsDataResolver + ?: ObjectManager::getInstance()->get(OptionsDataResolver::class); } /** @@ -134,7 +134,7 @@ public function __construct( public function execute() { try { - $optionData = $this->optionsDataProvider->getOptionsData($this->getRequest()); + $optionData = $this->optionsDataResolver->getOptionsData($this->getRequest()); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " . "If the error persists, please try again later."); @@ -149,7 +149,6 @@ public function execute() ); if ($data) { - $this->preprocessOptionsData($data); $setId = $this->getRequest()->getParam('set'); $attributeSet = null; @@ -339,20 +338,6 @@ public function execute() return $this->returnResult('catalog/*/', [], ['error' => true]); } - /** - * Extract options data from serialized options field and append to data array. - * - * This logic is required to overcome max_input_vars php limit - * that may vary and/or be inaccessible to change on different instances. - * - * @param array $data - * @return void - */ - private function preprocessOptionsData(&$data) - { - - } - /** * @param string $path * @param array $params diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index 35cc2a903bc96..fa8103f703367 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -7,7 +7,7 @@ namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataProvider; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataResolver; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; @@ -31,9 +31,9 @@ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute private $multipleAttributeList; /** - * @var OptionsDataProvider|null + * @var OptionsDataResolver|null */ - private $optionsDataProvider; + private $optionsDataResolver; /** * Constructor @@ -45,7 +45,7 @@ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\View\LayoutFactory $layoutFactory * @param array $multipleAttributeList - * @param OptionsDataProvider|null $optionsDataProvider + * @param OptionsDataResolver|null $optionsDataResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -55,14 +55,14 @@ public function __construct( \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, \Magento\Framework\View\LayoutFactory $layoutFactory, array $multipleAttributeList = [], - OptionsDataProvider $optionsDataProvider = null + OptionsDataResolver $optionsDataResolver = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; $this->multipleAttributeList = $multipleAttributeList; - $this->optionsDataProvider = $optionsDataProvider ?: ObjectManager::getInstance() - ->get(OptionsDataProvider::class); + $this->optionsDataResolver = $optionsDataResolver ?: ObjectManager::getInstance() + ->get(OptionsDataResolver::class); } /** @@ -75,9 +75,9 @@ public function execute() $response = new DataObject(); $response->setError(false); try { - $optionsData = $this->optionsDataProvider->getOptionsData($this->getRequest()); + $optionsData = $this->optionsDataResolver->getOptionsData($this->getRequest()); } catch (\InvalidArgumentException $e) { - $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " + $message = __("The attribute couldn't be validated due to an error. Verify your information and try again. " . "If the error persists, please try again later."); $this->setMessageToResponse($response, [$message]); $response->setError(true); diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php similarity index 88% rename from app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php rename to app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php index a2a1fcb7fb526..20e713be9a440 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataProvider.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php @@ -8,9 +8,14 @@ use Magento\Framework\App\RequestInterface; -class OptionsDataProvider +/** + * Attribute options data resolver. + */ +class OptionsDataResolver { /** + * Provides attribute options data from the request. + * * @param RequestInterface $request * @return array * @throws \InvalidArgumentException @@ -36,4 +41,4 @@ public function getOptionsData(RequestInterface $request): array return $optionsData; } -} \ No newline at end of file +} diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js index 233f554512f8c..bb06d05371e09 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js @@ -20,7 +20,6 @@ define([ return function (config) { var optionPanel = jQuery('#manage-options-panel'), - optionsValues = [], editForm = jQuery('#edit_form'), attributeOption = { table: $('attribute-options-table'), @@ -146,8 +145,7 @@ define([ return optionDefaultInputType; } }, - optionsTableContent = jQuery(), - optionContainer = optionPanel.find('table tbody'); + tableBody = jQuery(); if ($('add_new_option_button')) { Event.observe('add_new_option_button', 'click', attributeOption.add.bind(attributeOption, {}, true)); @@ -183,6 +181,9 @@ define([ }); } editForm.on('beforeSubmit', function () { + var optionsValues = [], + optionContainer = optionPanel.find('table tbody'); + if (optionPanel.is(':visible')) { optionContainer.find('input') .each(function () { @@ -206,13 +207,12 @@ define([ .val(JSON.stringify(optionsValues)) .prependTo(editForm); } - optionsTableContent = optionContainer.clone(true); - optionContainer - .replaceWith(jQuery('<div>').text(jQuery.mage.__('Sending attribute values as package.'))); + tableBody = optionContainer.detach(); }); editForm.on('afterValidate.error', function () { if (optionPanel.is(':visible')) { - optionContainer.replaceWith(optionsTableContent); + optionPanel.find('table').append(tableBody); + jQuery('input[name="serialized_options"]').remove(); } }); window.attributeOption = attributeOption; diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index dd1fb4b0a8b54..49723f4190a92 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -417,8 +417,7 @@ define([ var editForm = $('#edit_form'), swatchVisualPanel = $('#swatch-visual-options-panel'), swatchTextPanel = $('#swatch-text-options-panel'), - optionsTableContent = $(), - optionContainer = $(), + tableBody = $(), activePanel = $(); $('#frontend_input').bind('change', function () { @@ -436,7 +435,8 @@ define([ .collapse('hide'); editForm.on('beforeSubmit', function () { - var swatchValues = []; + var swatchValues = [], + optionContainer; activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel; optionContainer = activePanel.find('table tbody'); @@ -457,16 +457,13 @@ define([ .prependTo(editForm); } - optionsTableContent = optionContainer.clone(true); - [swatchVisualPanel, swatchTextPanel].forEach(function (el) { - $(el).find('table') - .replaceWith($('<div>').text($.mage.__('Sending swatch values as package.'))); - }); + tableBody = optionContainer.detach(); }); editForm.on('afterValidate.error', function () { if (activePanel.is(':visible')) { - optionContainer.replaceWith(optionsTableContent); + activePanel.find('table').append(tableBody); + $('input[name="serialized_options"]').remove(); } }); }); From 897c616e51405900ed0dcce2b21d68d547c085c1 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Tue, 11 Sep 2018 16:10:50 -0500 Subject: [PATCH 024/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Attribute/Option/OptionsDataResolver.php | 4 +- .../AdminProductAttributeActionGroup.xml | 5 +- .../AdminCreateProductAttributeSection.xml | 9 +++ .../Test/Mftf/Data/SwatchAttributeData.xml | 1 + ...ateVisualSwatchWithNonValidOptionsTest.xml | 74 +++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php index 20e713be9a440..60b183db9410a 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php @@ -4,6 +4,8 @@ * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Product\Attribute\Option; use Magento\Framework\App\RequestInterface; @@ -26,7 +28,7 @@ public function getOptionsData(RequestInterface $request): array $optionsData = []; if ($serializedOptions) { - $encodedOptions = json_decode($serializedOptions, JSON_OBJECT_AS_ARRAY); + $encodedOptions = json_decode($serializedOptions, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new \InvalidArgumentException('Unable to unserialize options data.'); diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index fd80838692065..23687484f1012 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -14,7 +14,10 @@ </arguments> <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <click selector="{{AdminProductAttributeGridSection.AttributeCode(ProductAttribute.attribute_code)}}" stepKey="navigateToAttributeEditPage1" /> + <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" + userInput="{{ProductAttribute.attribute_code}}" stepKey="setAttributeCode"/> + <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="searchForAttributeFromTheGrid"/> + <click selector="{{AdminProductAttributeGridSection.FirstRow}}" stepKey="clickOnAttributeRow"/> <waitForPageLoad stepKey="waitForPageLoad2" /> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml index b83676c2e1033..a497233afbd4e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml @@ -17,6 +17,7 @@ <element name="DefaultValue" type="input" selector="#default_value_text"/> <element name="Scope" type="select" selector="#is_global"/> <element name="Save" type="button" selector="#save" timeout="30"/> + <element name="DeleteAttribute" type="button" selector="#delete" timeout="30"/> <element name="SaveAndEdit" type="button" selector="#save_and_edit_button" timeout="30"/> <element name="TinyMCE4" type="button" selector="//span[text()='Default Value']/parent::label/following-sibling::div//div[@class='mce-branding-powered-by']"/> <element name="checkIfTabOpen" selector="//div[@id='advanced_fieldset-wrapper' and not(contains(@class,'opened'))]" type="button"/> @@ -63,4 +64,12 @@ <element name="SpecialCharacter" type="button" selector=".mce-i-charmap" /> <element name="TextArea" type="input" selector="#default_value_textarea" /> </section> + <section name="AdvancedAttributePropertiesSection"> + <element name="AdvancedAttributePropertiesSectionToggle" + type="button" selector="#advanced_fieldset-wrapper"/> + <element name="AttributeCode" type="text" selector="#attribute_code"/> + <element name="Scope" type="select" selector="#is_global"/> + <element name="AddToColumnOptions" type="select" selector="#is_used_in_grid"/> + <element name="UseInFilterOptions" type="select" selector="#is_filterable_in_grid"/> + </section> </sections> diff --git a/app/code/Magento/Swatches/Test/Mftf/Data/SwatchAttributeData.xml b/app/code/Magento/Swatches/Test/Mftf/Data/SwatchAttributeData.xml index 08e24cfeb38fe..d7ee6dabce7ed 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Data/SwatchAttributeData.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Data/SwatchAttributeData.xml @@ -11,5 +11,6 @@ <entity name="visualSwatchAttribute" type="SwatchAttribute"> <data key="default_label" unique="suffix">VisualSwatchAttr</data> <data key="input_type">Visual Swatch</data> + <data key="attribute_code" unique="suffix">visual_swatch_attr</data> </entity> </entities> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml new file mode 100644 index 0000000000000..00de4cdf937b5 --- /dev/null +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml @@ -0,0 +1,74 @@ +<?xml version="1.0"?> +<!-- +/** + * 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="AdminCreateVisualSwatchWithNonValidOptionsTest"> + <annotations> + <features value="Swatches"/> + <stories value="Create/configure swatches product attribute"/> + <title value="Admin should be able to create swatch product attribute"/> + <description value="Admin should be able to create swatch product attribute"/> + <severity value="BLOCKER"/> + <testCaseId value="MC-4140"/> + <group value="Swatches"/> + </annotations> + <before> + <actionGroup ref="LoginActionGroup" stepKey="login"/> + </before> + <after> + <!-- Remove attribute --> + <actionGroup ref="navigateToCreatedProductAttribute" stepKey="navigateToAttribute"> + <argument name="ProductAttribute" value="visualSwatchAttribute"/> + </actionGroup> + <click selector="{{AttributePropertiesSection.DeleteAttribute}}" stepKey="deleteAttribute"/> + + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <amOnPage url="{{ProductAttributePage.url}}" stepKey="navigateToNewProductAttributePage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + + <!-- Set attribute properties --> + <fillField selector="{{AttributePropertiesSection.DefaultLabel}}" + userInput="{{visualSwatchAttribute.default_label}}" stepKey="fillDefaultLabel"/> + <selectOption selector="{{AttributePropertiesSection.InputType}}" + userInput="{{visualSwatchAttribute.input_type}}" stepKey="fillInputType"/> + + <!-- Set advanced attribute properties --> + <click selector="{{AdvancedAttributePropertiesSection.AdvancedAttributePropertiesSectionToggle}}" + stepKey="showAdvancedAttributePropertiesSection"/> + <waitForElementVisible selector="{{AdvancedAttributePropertiesSection.AttributeCode}}" + stepKey="waitForSlideOut"/> + <fillField selector="{{AdvancedAttributePropertiesSection.AttributeCode}}" + userInput="{{visualSwatchAttribute.attribute_code}}" + stepKey="fillAttributeCode"/> + + <!-- Add an empty swatch option --> + <click selector="{{AdminManageSwatchSection.addSwatch}}" stepKey="clickAddSwatch1"/> + + <!-- Save the new product attribute --> + <click selector="{{AttributePropertiesSection.Save}}" stepKey="clickSave1"/> + <waitForElementVisible selector="{{AdminProductMessagesSection.errorMessage}}" stepKey="waitForError"/> + + <!-- Fill options data --> + <actionGroup ref="openSwatchMenuByIndex" stepKey="clickSwatch2"> + <argument name="index" value="0"/> + </actionGroup> + <click selector="{{AdminManageSwatchSection.nthChooseColor('1')}}" stepKey="clickChooseColor1"/> + <actionGroup ref="setColorPickerByHex" stepKey="fillHex1"> + <argument name="nthColorPicker" value="1"/> + <argument name="hexColor" value="ff0000"/> + </actionGroup> + <fillField selector="{{AdminManageSwatchSection.adminInputByIndex('0')}}" + userInput="red" stepKey="fillAdmin1"/> + + <!-- Save the new product attribute --> + <click selector="{{AttributePropertiesSection.Save}}" stepKey="clickSave2"/> + <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" + stepKey="waitForSuccessMessage"/> + </test> +</tests> \ No newline at end of file From 758d65da91f7182ca7cea5bc05f424c34cba8227 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Tue, 11 Sep 2018 17:28:12 -0500 Subject: [PATCH 025/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Controller/Adminhtml/Product/Attribute/Validate.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index fa8103f703367..9fcfe39f6dd9e 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -11,6 +11,9 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute { const DEFAULT_MESSAGE_KEY = 'message'; From 5a283e3ff98079a94249bd3430c945484d8859c1 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Wed, 12 Sep 2018 15:31:57 -0500 Subject: [PATCH 026/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Product/Attribute/ValidateTest.php | 167 +++++++++++------- .../catalog/product/attribute/js.phtml | 5 +- .../Catalog/view/adminhtml/web/js/options.js | 7 +- ...ateVisualSwatchWithNonValidOptionsTest.xml | 14 +- .../adminhtml/web/js/product-attributes.js | 11 +- .../Adminhtml/Product/AttributeTest.php | 17 +- 6 files changed, 134 insertions(+), 87 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php index 9c747393cc72a..60c79a044812a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php @@ -6,6 +6,7 @@ namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Controller\Adminhtml\Product\Attribute\Validate; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataResolver; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest; use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet; @@ -61,6 +62,11 @@ class ValidateTest extends AttributeTest */ protected $layoutMock; + /** + * @var OptionsDataResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $optionsDataResolverMock; + protected function setUp() { parent::setUp(); @@ -86,6 +92,8 @@ protected function setUp() ->getMock(); $this->layoutMock = $this->getMockBuilder(LayoutInterface::class) ->getMockForAbstractClass(); + $this->optionsDataResolverMock = $this->getMockBuilder(OptionsDataResolver::class) + ->getMock(); $this->contextMock->expects($this->any()) ->method('getObjectManager') @@ -100,13 +108,14 @@ protected function getModel() return $this->objectManager->getObject( Validate::class, [ - 'context' => $this->contextMock, - 'attributeLabelCache' => $this->attributeLabelCacheMock, - 'coreRegistry' => $this->coreRegistryMock, - 'resultPageFactory' => $this->resultPageFactoryMock, - 'resultJsonFactory' => $this->resultJsonFactoryMock, - 'layoutFactory' => $this->layoutFactoryMock, - 'multipleAttributeList' => ['select' => 'option'] + 'context' => $this->contextMock, + 'attributeLabelCache' => $this->attributeLabelCacheMock, + 'coreRegistry' => $this->coreRegistryMock, + 'resultPageFactory' => $this->resultPageFactoryMock, + 'resultJsonFactory' => $this->resultJsonFactoryMock, + 'layoutFactory' => $this->layoutFactoryMock, + 'multipleAttributeList' => ['select' => 'option'], + 'optionsDataResolver' => $this->optionsDataResolverMock, ] ); } @@ -160,17 +169,22 @@ public function testExecute() */ public function testUniqueValidation(array $options, $isError) { - $countFunctionCalls = ($isError) ? 6 : 5; + $countFunctionCalls = ($isError) ? 5 : 4; $this->requestMock->expects($this->exactly($countFunctionCalls)) ->method('getParam') ->willReturnMap([ ['frontend_label', null, null], ['attribute_code', null, "test_attribute_code"], ['new_attribute_set_name', null, 'test_attribute_set_name'], - ['option', null, $options], ['message_key', null, Validate::DEFAULT_MESSAGE_KEY] ]); + $this->optionsDataResolverMock + ->expects($this->once()) + ->method('getOptionsData') + ->with($this->requestMock) + ->willReturn($options); + $this->objectManagerMock->expects($this->once()) ->method('create') ->willReturn($this->attributeMock); @@ -203,67 +217,77 @@ public function provideUniqueData() return [ 'no values' => [ [ - 'delete' => [ - "option_0" => "", - "option_1" => "", - "option_2" => "", - ] + 'option' => [ + 'delete' => [ + "option_0" => "", + "option_1" => "", + "option_2" => "", + ], + ], ], false ], 'valid options' => [ [ - 'value' => [ - "option_0" => [1, 0], - "option_1" => [2, 0], - "option_2" => [3, 0], + 'option' => [ + 'value' => [ + "option_0" => [1, 0], + "option_1" => [2, 0], + "option_2" => [3, 0], + ], + 'delete' => [ + "option_0" => "", + "option_1" => "", + "option_2" => "", + ], ], - 'delete' => [ - "option_0" => "", - "option_1" => "", - "option_2" => "", - ] ], false ], 'duplicate options' => [ [ - 'value' => [ - "option_0" => [1, 0], - "option_1" => [1, 0], - "option_2" => [3, 0], + 'option' => [ + 'value' => [ + "option_0" => [1, 0], + "option_1" => [1, 0], + "option_2" => [3, 0], + ], + 'delete' => [ + "option_0" => "", + "option_1" => "", + "option_2" => "", + ], ], - 'delete' => [ - "option_0" => "", - "option_1" => "", - "option_2" => "", - ] ], true ], 'duplicate and deleted' => [ [ - 'value' => [ - "option_0" => [1, 0], - "option_1" => [1, 0], - "option_2" => [3, 0], + 'option' => [ + 'value' => [ + "option_0" => [1, 0], + "option_1" => [1, 0], + "option_2" => [3, 0], + ], + 'delete' => [ + "option_0" => "", + "option_1" => "1", + "option_2" => "", + ], ], - 'delete' => [ - "option_0" => "", - "option_1" => "1", - "option_2" => "", - ] ], false ], 'empty and deleted' => [ [ - 'value' => [ - "option_0" => [1, 0], - "option_1" => [2, 0], - "option_2" => ["", ""], + 'option' => [ + 'value' => [ + "option_0" => [1, 0], + "option_1" => [2, 0], + "option_2" => ["", ""], + ], + 'delete' => [ + "option_0" => "", + "option_1" => "", + "option_2" => "1", + ], ], - 'delete' => [ - "option_0" => "", - "option_1" => "", - "option_2" => "1", - ] ], false ], ]; @@ -285,10 +309,15 @@ public function testEmptyOption(array $options, $result) ['frontend_input', 'select', 'multipleselect'], ['attribute_code', null, "test_attribute_code"], ['new_attribute_set_name', null, 'test_attribute_set_name'], - ['option', null, $options], ['message_key', Validate::DEFAULT_MESSAGE_KEY, 'message'], ]); + $this->optionsDataResolverMock + ->expects($this->once()) + ->method('getOptionsData') + ->with($this->requestMock) + ->willReturn($options); + $this->objectManagerMock->expects($this->once()) ->method('create') ->willReturn($this->attributeMock); @@ -320,8 +349,10 @@ public function provideEmptyOption() return [ 'empty admin scope options' => [ [ - 'value' => [ - "option_0" => [''], + 'option' => [ + 'value' => [ + "option_0" => [''], + ], ], ], (object) [ @@ -331,8 +362,10 @@ public function provideEmptyOption() ], 'not empty admin scope options' => [ [ - 'value' => [ - "option_0" => ['asdads'], + 'option' => [ + 'value' => [ + "option_0" => ['asdads'], + ], ], ], (object) [ @@ -341,11 +374,13 @@ public function provideEmptyOption() ], 'empty admin scope options and deleted' => [ [ - 'value' => [ - "option_0" => [''], - ], - 'delete' => [ - 'option_0' => '1', + 'option' => [ + 'value' => [ + "option_0" => [''], + ], + 'delete' => [ + 'option_0' => '1', + ], ], ], (object) [ @@ -354,11 +389,13 @@ public function provideEmptyOption() ], 'empty admin scope options and not deleted' => [ [ - 'value' => [ - "option_0" => [''], - ], - 'delete' => [ - 'option_0' => '0', + 'option' => [ + 'value' => [ + "option_0" => [''], + ], + 'delete' => [ + 'option_0' => '0', + ], ], ], (object) [ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/js.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/js.phtml index 8a5f1919f78be..eeacc90fba914 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/js.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/js.phtml @@ -40,13 +40,16 @@ function getFrontTab() { function checkOptionsPanelVisibility(){ if($('manage-options-panel')){ - var panel = $('manage-options-panel').up('.fieldset'); + var panel = $('manage-options-panel').up('.fieldset'), + activePanelClass = 'selected-type-options'; if($('frontend_input') && ($('frontend_input').value=='select' || $('frontend_input').value=='multiselect')){ panel.show(); + panel.addClass(activePanelClass); } else { panel.hide(); + panel.removeClass(activePanelClass); } } } diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js index bb06d05371e09..7c35993670444 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js @@ -145,7 +145,8 @@ define([ return optionDefaultInputType; } }, - tableBody = jQuery(); + tableBody = jQuery(), + activePanelClass = 'selected-type-options'; if ($('add_new_option_button')) { Event.observe('add_new_option_button', 'click', attributeOption.add.bind(attributeOption, {}, true)); @@ -184,7 +185,7 @@ define([ var optionsValues = [], optionContainer = optionPanel.find('table tbody'); - if (optionPanel.is(':visible')) { + if (optionPanel.hasClass(activePanelClass)) { optionContainer.find('input') .each(function () { if (this.disabled) { @@ -210,7 +211,7 @@ define([ tableBody = optionContainer.detach(); }); editForm.on('afterValidate.error', function () { - if (optionPanel.is(':visible')) { + if (optionPanel.hasClass(activePanelClass)) { optionPanel.find('table').append(tableBody); jQuery('input[name="serialized_options"]').remove(); } diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml index 00de4cdf937b5..92a33487615ea 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml @@ -47,14 +47,8 @@ userInput="{{visualSwatchAttribute.attribute_code}}" stepKey="fillAttributeCode"/> - <!-- Add an empty swatch option --> + <!-- Add new swatch option without label --> <click selector="{{AdminManageSwatchSection.addSwatch}}" stepKey="clickAddSwatch1"/> - - <!-- Save the new product attribute --> - <click selector="{{AttributePropertiesSection.Save}}" stepKey="clickSave1"/> - <waitForElementVisible selector="{{AdminProductMessagesSection.errorMessage}}" stepKey="waitForError"/> - - <!-- Fill options data --> <actionGroup ref="openSwatchMenuByIndex" stepKey="clickSwatch2"> <argument name="index" value="0"/> </actionGroup> @@ -63,6 +57,12 @@ <argument name="nthColorPicker" value="1"/> <argument name="hexColor" value="ff0000"/> </actionGroup> + + <!-- Save the new product attribute --> + <click selector="{{AttributePropertiesSection.Save}}" stepKey="clickSave1"/> + <waitForElementVisible selector="{{AdminProductMessagesSection.errorMessage}}" stepKey="waitForError"/> + + <!-- Fill options data --> <fillField selector="{{AdminManageSwatchSection.adminInputByIndex('0')}}" userInput="red" stepKey="fillAdmin1"/> diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index 49723f4190a92..9538e8729e48d 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -16,7 +16,8 @@ define([ 'use strict'; return function (optionConfig) { - var swatchProductAttributes = { + var activePanelClass = 'selected-type-options', + swatchProductAttributes = { frontendInput: $('#frontend_input'), isFilterable: $('#is_filterable'), isFilterableInSearch: $('#is_filterable_in_search'), @@ -338,6 +339,7 @@ define([ */ _showPanel: function (el) { el.closest('.fieldset').show(); + el.addClass(activePanelClass); this._render(el.attr('id')); }, @@ -347,6 +349,7 @@ define([ */ _hidePanel: function (el) { el.closest('.fieldset').hide(); + el.removeClass(activePanelClass); }, /** @@ -438,10 +441,10 @@ define([ var swatchValues = [], optionContainer; - activePanel = swatchTextPanel.is(':visible') ? swatchTextPanel : swatchVisualPanel; + activePanel = swatchTextPanel.hasClass(this.activePanelClass) ? swatchTextPanel : swatchVisualPanel; optionContainer = activePanel.find('table tbody'); - if (activePanel.is(':visible')) { + if (activePanel.hasClass(activePanelClass)) { optionContainer .find('input') .each(function () { @@ -461,7 +464,7 @@ define([ }); editForm.on('afterValidate.error', function () { - if (activePanel.is(':visible')) { + if (activePanel.hasClass(activePanelClass)) { activePanel.find('table').append(tableBody); $('input[name="serialized_options"]').remove(); } diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php index 969d9530ae542..1a0073b154ffa 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php @@ -48,12 +48,14 @@ private function getSwatchVisualDataSet(int $optionsCount) : array $optionsData []= "optionvisual[value][option_{$i}][1]={$expectedOptionLabelOnStoreView}"; $optionsData []= "optionvisual[delete][option_{$i}]="; } - $optionsData []= "visual_swatch_validation="; - $optionsData []= "visual_swatch_validation_unique="; return [ 'attribute_data' => array_merge_recursive( [ - 'serialized_swatch_values' => json_encode($optionsData), + 'serialized_options' => json_encode($optionsData), + ], + [ + 'visual_swatch_validation' => '', + 'visual_swatch_validation_unique' => '', ], $this->getAttributePreset(), [ @@ -86,12 +88,14 @@ private function getSwatchTextDataSet(int $optionsCount) : array $optionsData []= "optiontext[value][option_{$i}][1]={$expectedOptionLabelOnStoreView}"; $optionsData []= "optiontext[delete][option_{$i}]="; } - $optionsData []= "text_swatch_validation="; - $optionsData []= "text_swatch_validation_unique="; return [ 'attribute_data' => array_merge_recursive( [ - 'serialized_swatch_values' => json_encode($optionsData), + 'serialized_options' => json_encode($optionsData), + ], + [ + 'text_swatch_validation' => '', + 'text_swatch_validation_unique' => '', ], $this->getAttributePreset(), [ @@ -111,7 +115,6 @@ private function getSwatchTextDataSet(int $optionsCount) : array private function getAttributePreset() : array { return [ - 'serialized_options' => '[]', 'form_key' => 'XxtpPYjm2YPYUlAt', 'frontend_label' => [ 0 => 'asdasd', From 1acda9bc30580ad73f8ce239a34fb8eea7c25ae5 Mon Sep 17 00:00:00 2001 From: Volodymyr Kublytskyi <vkublytskyi@magento.com> Date: Fri, 14 Sep 2018 13:45:51 +0300 Subject: [PATCH 027/118] magento/bulk-api-ce#14: The user passed for async api should reference WebAPI user - applied backward compatibility policy to modified constructors --- .../AsynchronousOperations/Model/BulkManagement.php | 8 +++++--- .../Magento/AsynchronousOperations/Model/MassSchedule.php | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php index 1d7d15f84163f..faf01921e5737 100644 --- a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php +++ b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php @@ -5,6 +5,7 @@ */ namespace Magento\AsynchronousOperations\Model; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface; use Magento\AsynchronousOperations\Api\Data\BulkSummaryInterfaceFactory; @@ -71,6 +72,7 @@ class BulkManagement implements \Magento\Framework\Bulk\BulkManagementInterface * @param MetadataPool $metadataPool * @param ResourceConnection $resourceConnection * @param \Psr\Log\LoggerInterface $logger + * @param UserContextInterface $userContext */ public function __construct( EntityManager $entityManager, @@ -79,8 +81,8 @@ public function __construct( BulkPublisherInterface $publisher, MetadataPool $metadataPool, ResourceConnection $resourceConnection, - UserContextInterface $userContext, - \Psr\Log\LoggerInterface $logger + \Psr\Log\LoggerInterface $logger, + UserContextInterface $userContext = null ) { $this->entityManager = $entityManager; $this->bulkSummaryFactory= $bulkSummaryFactory; @@ -88,8 +90,8 @@ public function __construct( $this->metadataPool = $metadataPool; $this->resourceConnection = $resourceConnection; $this->publisher = $publisher; - $this->userContext = $userContext; $this->logger = $logger; + $this->userContext = $userContext ?: ObjectManager::getInstance()->get(UserContextInterface::class); } /** diff --git a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php index 5f792d1729ca4..28a360adc5101 100644 --- a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php +++ b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php @@ -8,6 +8,7 @@ namespace Magento\AsynchronousOperations\Model; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject\IdentityGeneratorInterface; use Magento\Framework\Exception\LocalizedException; use Magento\AsynchronousOperations\Api\Data\ItemStatusInterfaceFactory; @@ -69,6 +70,7 @@ class MassSchedule * @param BulkManagementInterface $bulkManagement * @param LoggerInterface $logger * @param OperationRepository $operationRepository + * @param UserContextInterface $userContext */ public function __construct( IdentityGeneratorInterface $identityService, @@ -77,7 +79,7 @@ public function __construct( BulkManagementInterface $bulkManagement, LoggerInterface $logger, OperationRepository $operationRepository, - UserContextInterface $userContext + UserContextInterface $userContext = null ) { $this->identityService = $identityService; $this->itemStatusInterfaceFactory = $itemStatusInterfaceFactory; @@ -85,7 +87,7 @@ public function __construct( $this->bulkManagement = $bulkManagement; $this->logger = $logger; $this->operationRepository = $operationRepository; - $this->userContext = $userContext; + $this->userContext = $userContext ?: ObjectManager::getInstance()->get(UserContextInterface::class); } /** From aafc793f5d22ac7d087a1e04919f95f7378a2e46 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Thu, 13 Sep 2018 17:21:01 -0500 Subject: [PATCH 028/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Adminhtml/Product/Attribute/Save.php | 17 ++++--- .../Adminhtml/Product/Attribute/Validate.php | 17 ++++--- .../Attribute/Option/OptionsDataResolver.php | 46 ----------------- .../Option/OptionsDataSerializer.php | 50 +++++++++++++++++++ .../adminhtml/web/js/product-attributes.js | 2 +- 5 files changed, 69 insertions(+), 63 deletions(-) delete mode 100644 app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php create mode 100644 app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 825288b366410..0c6b2cb52e1a3 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -13,7 +13,7 @@ use Magento\Catalog\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Helper\Product; use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataResolver; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; use Magento\Catalog\Model\Product\AttributeSet\BuildFactory; use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory; use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator; @@ -77,9 +77,9 @@ class Save extends Attribute private $presentation; /** - * @var OptionsDataResolver|null + * @var OptionsDataSerializer|null */ - private $optionsDataResolver; + private $optionsDataSerializer; /** * @param Context $context @@ -94,7 +94,7 @@ class Save extends Attribute * @param Product $productHelper * @param LayoutFactory $layoutFactory * @param Presentation|null $presentation - * @param OptionsDataResolver|null $optionsDataResolver + * @param OptionsDataSerializer|null $optionsDataSerializer * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -110,7 +110,7 @@ public function __construct( Product $productHelper, LayoutFactory $layoutFactory, Presentation $presentation = null, - OptionsDataResolver $optionsDataResolver = null + OptionsDataSerializer $optionsDataSerializer = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->buildFactory = $buildFactory; @@ -121,8 +121,8 @@ public function __construct( $this->groupCollectionFactory = $groupCollectionFactory; $this->layoutFactory = $layoutFactory; $this->presentation = $presentation ?: ObjectManager::getInstance()->get(Presentation::class); - $this->optionsDataResolver = $optionsDataResolver - ?: ObjectManager::getInstance()->get(OptionsDataResolver::class); + $this->optionsDataSerializer = $optionsDataSerializer + ?: ObjectManager::getInstance()->get(OptionsDataSerializer::class); } /** @@ -134,7 +134,8 @@ public function __construct( public function execute() { try { - $optionData = $this->optionsDataResolver->getOptionsData($this->getRequest()); + $optionData = $this->optionsDataSerializer + ->unserialize($this->getRequest()->getParam('serialized_options')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " . "If the error persists, please try again later."); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index 9fcfe39f6dd9e..ca2ba9d231a33 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -7,7 +7,7 @@ namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataResolver; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; @@ -34,9 +34,9 @@ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute private $multipleAttributeList; /** - * @var OptionsDataResolver|null + * @var OptionsDataSerializer|null */ - private $optionsDataResolver; + private $optionsDataSerializer; /** * Constructor @@ -48,7 +48,7 @@ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\View\LayoutFactory $layoutFactory * @param array $multipleAttributeList - * @param OptionsDataResolver|null $optionsDataResolver + * @param OptionsDataSerializer|null $optionsDataSerializer */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -58,14 +58,14 @@ public function __construct( \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, \Magento\Framework\View\LayoutFactory $layoutFactory, array $multipleAttributeList = [], - OptionsDataResolver $optionsDataResolver = null + OptionsDataSerializer $optionsDataSerializer = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; $this->multipleAttributeList = $multipleAttributeList; - $this->optionsDataResolver = $optionsDataResolver ?: ObjectManager::getInstance() - ->get(OptionsDataResolver::class); + $this->optionsDataSerializer = $optionsDataSerializer ?: ObjectManager::getInstance() + ->get(OptionsDataSerializer::class); } /** @@ -78,7 +78,8 @@ public function execute() $response = new DataObject(); $response->setError(false); try { - $optionsData = $this->optionsDataResolver->getOptionsData($this->getRequest()); + $optionsData = $this->optionsDataSerializer + ->unserialize($this->getRequest()->getParam('serialized_options')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be validated due to an error. Verify your information and try again. " . "If the error persists, please try again later."); diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php deleted file mode 100644 index 60b183db9410a..0000000000000 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataResolver.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -declare(strict_types=1); - -namespace Magento\Catalog\Model\Product\Attribute\Option; - -use Magento\Framework\App\RequestInterface; - -/** - * Attribute options data resolver. - */ -class OptionsDataResolver -{ - /** - * Provides attribute options data from the request. - * - * @param RequestInterface $request - * @return array - * @throws \InvalidArgumentException - */ - public function getOptionsData(RequestInterface $request): array - { - $serializedOptions = $request->getParam('serialized_options'); - $optionsData = []; - - if ($serializedOptions) { - $encodedOptions = json_decode($serializedOptions, true); - - if (json_last_error() !== JSON_ERROR_NONE) { - throw new \InvalidArgumentException('Unable to unserialize options data.'); - } - - foreach ($encodedOptions as $encodedOption) { - $decodedOptionData = []; - parse_str($encodedOption, $decodedOptionData); - $optionsData = array_replace_recursive($optionsData, $decodedOptionData); - } - } - - return $optionsData; - } -} diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php new file mode 100644 index 0000000000000..8fe02a9123b18 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Catalog\Model\Product\Attribute\Option; + +use Magento\Framework\Serialize\SerializerInterface; + +/** + * Attribute options data serializer. + */ +class OptionsDataSerializer +{ + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @param SerializerInterface $serializer + */ + public function __construct(SerializerInterface $serializer) + { + $this->serializer = $serializer; + } + + /** + * Provides attribute options data from the serialized data. + * + * @param string $serializedOptions + * @return array + */ + public function unserialize(string $serializedOptions): array + { + $optionsData = []; + $encodedOptions = $this->serializer->unserialize($serializedOptions); + + foreach ($encodedOptions as $encodedOption) { + $decodedOptionData = []; + parse_str($encodedOption, $decodedOptionData); + $optionsData = array_replace_recursive($optionsData, $decodedOptionData); + } + + return $optionsData; + } +} diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index 9538e8729e48d..d0eacc94e2c32 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -441,7 +441,7 @@ define([ var swatchValues = [], optionContainer; - activePanel = swatchTextPanel.hasClass(this.activePanelClass) ? swatchTextPanel : swatchVisualPanel; + activePanel = swatchTextPanel.hasClass(activePanelClass) ? swatchTextPanel : swatchVisualPanel; optionContainer = activePanel.find('table tbody'); if (activePanel.hasClass(activePanelClass)) { From efceb14099aee0a388c20c4a9696e6e6b67ee8ee Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Fri, 14 Sep 2018 09:37:21 -0500 Subject: [PATCH 029/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Adminhtml/Product/Attribute/SaveTest.php | 130 ++++++++++++++++++ .../Product/Attribute/ValidateTest.php | 84 +++++++++-- .../Adminhtml/Product/AttributeTest.php | 19 ++- 3 files changed, 217 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php index f493cbc88f18e..b9b1aeb9157db 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php @@ -5,7 +5,9 @@ */ namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Attribute; +use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Catalog\Controller\Adminhtml\Product\Attribute\Save; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest; use Magento\Catalog\Model\Product\AttributeSet\BuildFactory; use Magento\Catalog\Model\Product\AttributeSet\Build; @@ -13,11 +15,14 @@ use Magento\Eav\Api\Data\AttributeSetInterface; use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\ValidatorFactory; use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory; +use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Filter\FilterManager; use Magento\Catalog\Helper\Product as ProductHelper; +use Magento\Framework\View\Element\Messages; use Magento\Framework\View\LayoutFactory; use Magento\Backend\Model\View\Result\Redirect as ResultRedirect; use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator as InputTypeValidator; +use Magento\Framework\View\LayoutInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -79,6 +84,16 @@ class SaveTest extends AttributeTest */ protected $inputTypeValidatorMock; + /** + * @var OptionsDataSerializer|\PHPUnit_Framework_MockObject_MockObject + */ + private $optionsDataSerializerMock; + + /** + * @var ProductAttributeInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productAttributeMock; + protected function setUp() { parent::setUp(); @@ -108,6 +123,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); $this->redirectMock = $this->getMockBuilder(ResultRedirect::class) + ->setMethods(['setData', 'setPath']) ->disableOriginalConstructor() ->getMock(); $this->attributeSetMock = $this->getMockBuilder(AttributeSetInterface::class) @@ -119,6 +135,12 @@ protected function setUp() $this->inputTypeValidatorMock = $this->getMockBuilder(InputTypeValidator::class) ->disableOriginalConstructor() ->getMock(); + $this->optionsDataSerializerMock = $this->getMockBuilder(OptionsDataSerializer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productAttributeMock = $this->getMockBuilder(ProductAttributeInterface::class) + ->setMethods(['getId', 'get']) + ->getMockForAbstractClass(); $this->buildFactoryMock->expects($this->any()) ->method('create') @@ -126,6 +148,9 @@ protected function setUp() $this->validatorFactoryMock->expects($this->any()) ->method('create') ->willReturn($this->inputTypeValidatorMock); + $this->attributeFactoryMock + ->method('create') + ->willReturn($this->productAttributeMock); } /** @@ -145,11 +170,23 @@ protected function getModel() 'validatorFactory' => $this->validatorFactoryMock, 'groupCollectionFactory' => $this->groupCollectionFactoryMock, 'layoutFactory' => $this->layoutFactoryMock, + 'optionsDataSerializer' => $this->optionsDataSerializerMock, ]); } public function testExecuteWithEmptyData() { + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['isAjax', null, null], + ['serialized_options', null, ''], + ]); + $this->optionsDataSerializerMock + ->expects($this->once()) + ->method('unserialize') + ->with('') + ->willReturn([]); $this->requestMock->expects($this->once()) ->method('getPostValue') ->willReturn([]); @@ -170,6 +207,23 @@ public function testExecute() 'frontend_input' => 'test_frontend_input', ]; + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['isAjax', null, null], + ['serialized_options', null, ''], + ]); + $this->optionsDataSerializerMock + ->expects($this->once()) + ->method('unserialize') + ->with('') + ->willReturn([]); + $this->productAttributeMock + ->method('getId') + ->willReturn(1); + $this->productAttributeMock + ->method('getAttributeCode') + ->willReturn('test_code'); $this->requestMock->expects($this->once()) ->method('getPostValue') ->willReturn($data); @@ -203,4 +257,80 @@ public function testExecute() $this->assertInstanceOf(ResultRedirect::class, $this->getModel()->execute()); } + + /** + * @throws \Magento\Framework\Exception\NotFoundException + */ + public function testExecuteWithOptionsDataError() + { + $serializedOptions = '{"key":"value"}'; + $message = "The attribute couldn't be saved due to an error. Verify your information and try again. " + . "If the error persists, please try again later."; + + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['isAjax', null, true], + ['serialized_options', null, $serializedOptions], + ]); + $this->optionsDataSerializerMock + ->expects($this->once()) + ->method('unserialize') + ->with($serializedOptions) + ->willThrowException(new \InvalidArgumentException('Some exception')); + $this->messageManager + ->expects($this->once()) + ->method('addErrorMessage') + ->with($message); + $this->addReturnResultConditions('catalog/*/edit', ['_current' => true], ['error' => true]); + + $this->getModel()->execute(); + } + + /** + * @param string $path + * @param array $params + * @param array $response + * @return mixed + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + private function addReturnResultConditions(string $path = '', array $params = [], array $response = []) + { + $layoutMock = $this->getMockBuilder(LayoutInterface::class) + ->setMethods(['initMessages', 'getMessagesBlock']) + ->getMockForAbstractClass(); + $this->layoutFactoryMock + ->expects($this->once()) + ->method('create') + ->with() + ->willReturn($layoutMock); + $layoutMock + ->method('initMessages') + ->with(); + $messageBlockMock = $this->getMockBuilder(Messages::class) + ->disableOriginalConstructor() + ->getMock(); + $layoutMock + ->expects($this->once()) + ->method('getMessagesBlock') + ->willReturn($messageBlockMock); + $messageBlockMock + ->expects($this->once()) + ->method('getGroupedHtml') + ->willReturn('message1'); + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->redirectMock); + $response = array_merge($response, [ + 'messages' => ['message1'], + 'params' => $params, + ]); + $this->redirectMock + ->expects($this->once()) + ->method('setData') + ->with($response) + ->willReturnSelf(); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php index 60c79a044812a..e9fc8bf3362b3 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php @@ -6,7 +6,7 @@ namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Controller\Adminhtml\Product\Attribute\Validate; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataResolver; +use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest; use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet; @@ -63,9 +63,9 @@ class ValidateTest extends AttributeTest protected $layoutMock; /** - * @var OptionsDataResolver|\PHPUnit_Framework_MockObject_MockObject + * @var OptionsDataSerializer|\PHPUnit_Framework_MockObject_MockObject */ - private $optionsDataResolverMock; + private $optionsDataSerializerMock; protected function setUp() { @@ -92,7 +92,8 @@ protected function setUp() ->getMock(); $this->layoutMock = $this->getMockBuilder(LayoutInterface::class) ->getMockForAbstractClass(); - $this->optionsDataResolverMock = $this->getMockBuilder(OptionsDataResolver::class) + $this->optionsDataSerializerMock = $this->getMockBuilder(OptionsDataSerializer::class) + ->disableOriginalConstructor() ->getMock(); $this->contextMock->expects($this->any()) @@ -115,19 +116,21 @@ protected function getModel() 'resultJsonFactory' => $this->resultJsonFactoryMock, 'layoutFactory' => $this->layoutFactoryMock, 'multipleAttributeList' => ['select' => 'option'], - 'optionsDataResolver' => $this->optionsDataResolverMock, + 'optionsDataSerializer' => $this->optionsDataSerializerMock, ] ); } public function testExecute() { + $serializedOptions = '{"key":"value"}'; $this->requestMock->expects($this->any()) ->method('getParam') ->willReturnMap([ ['frontend_label', null, 'test_frontend_label'], ['attribute_code', null, 'test_attribute_code'], ['new_attribute_set_name', null, 'test_attribute_set_name'], + ['serialized_options', null, $serializedOptions], ]); $this->objectManagerMock->expects($this->exactly(2)) ->method('create') @@ -169,20 +172,22 @@ public function testExecute() */ public function testUniqueValidation(array $options, $isError) { - $countFunctionCalls = ($isError) ? 5 : 4; + $serializedOptions = '{"key":"value"}'; + $countFunctionCalls = ($isError) ? 6 : 5; $this->requestMock->expects($this->exactly($countFunctionCalls)) ->method('getParam') ->willReturnMap([ ['frontend_label', null, null], ['attribute_code', null, "test_attribute_code"], ['new_attribute_set_name', null, 'test_attribute_set_name'], - ['message_key', null, Validate::DEFAULT_MESSAGE_KEY] + ['message_key', null, Validate::DEFAULT_MESSAGE_KEY], + ['serialized_options', null, $serializedOptions], ]); - $this->optionsDataResolverMock + $this->optionsDataSerializerMock ->expects($this->once()) - ->method('getOptionsData') - ->with($this->requestMock) + ->method('unserialize') + ->with($serializedOptions) ->willReturn($options); $this->objectManagerMock->expects($this->once()) @@ -302,6 +307,7 @@ public function provideUniqueData() */ public function testEmptyOption(array $options, $result) { + $serializedOptions = '{"key":"value"}'; $this->requestMock->expects($this->any()) ->method('getParam') ->willReturnMap([ @@ -310,12 +316,13 @@ public function testEmptyOption(array $options, $result) ['attribute_code', null, "test_attribute_code"], ['new_attribute_set_name', null, 'test_attribute_set_name'], ['message_key', Validate::DEFAULT_MESSAGE_KEY, 'message'], + ['serialized_options', null, $serializedOptions], ]); - $this->optionsDataResolverMock + $this->optionsDataSerializerMock ->expects($this->once()) - ->method('getOptionsData') - ->with($this->requestMock) + ->method('unserialize') + ->with($serializedOptions) ->willReturn($options); $this->objectManagerMock->expects($this->once()) @@ -405,4 +412,55 @@ public function provideEmptyOption() ], ]; } + + /** + * @throws \Magento\Framework\Exception\NotFoundException + */ + public function testExecuteWithOptionsDataError() + { + $serializedOptions = '{"key":"value"}'; + $message = "The attribute couldn't be validated due to an error. Verify your information and try again. " + . "If the error persists, please try again later."; + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['frontend_label', null, 'test_frontend_label'], + ['attribute_code', null, 'test_attribute_code'], + ['new_attribute_set_name', null, 'test_attribute_set_name'], + ['message_key', Validate::DEFAULT_MESSAGE_KEY, 'message'], + ['serialized_options', null, $serializedOptions], + ]); + + $this->optionsDataSerializerMock + ->expects($this->once()) + ->method('unserialize') + ->with($serializedOptions) + ->willThrowException(new \InvalidArgumentException('Some exception')); + + $this->objectManagerMock + ->method('create') + ->willReturnMap([ + [\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, [], $this->attributeMock], + [\Magento\Eav\Model\Entity\Attribute\Set::class, [], $this->attributeSetMock] + ]); + + $this->attributeMock + ->method('loadByCode') + ->willReturnSelf(); + $this->attributeSetMock + ->method('setEntityTypeId') + ->willReturnSelf(); + $this->resultJsonFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->resultJson); + $this->resultJson->expects($this->once()) + ->method('setJsonData') + ->with(json_encode([ + 'error' => true, + 'message' => $message + ])) + ->willReturnSelf(); + + $this->getModel()->execute(); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AttributeTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AttributeTest.php index b85b03852b621..2a75773754fca 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AttributeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AttributeTest.php @@ -9,8 +9,10 @@ use Magento\Catalog\Controller\Adminhtml\Product\Attribute; use Magento\Framework\App\RequestInterface; use Magento\Framework\Cache\FrontendInterface; +use Magento\Framework\Message\ManagerInterface; +use Magento\Framework\ObjectManager\ObjectManager; use Magento\Framework\Registry; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use Magento\Framework\View\Result\PageFactory; use Magento\Framework\Controller\ResultFactory; @@ -20,7 +22,7 @@ class AttributeTest extends \PHPUnit\Framework\TestCase { /** - * @var ObjectManager + * @var ObjectManagerHelper */ protected $objectManager; @@ -54,9 +56,14 @@ class AttributeTest extends \PHPUnit\Framework\TestCase */ protected $resultFactoryMock; + /** + * @var ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $messageManager; + protected function setUp() { - $this->objectManager = new ObjectManager($this); + $this->objectManager = new ObjectManagerHelper($this); $this->contextMock = $this->getMockBuilder(Context::class) ->disableOriginalConstructor() ->getMock(); @@ -74,6 +81,9 @@ protected function setUp() $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) ->disableOriginalConstructor() ->getMock(); + $this->messageManager = $this->getMockBuilder(ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); $this->contextMock->expects($this->any()) ->method('getRequest') @@ -81,6 +91,9 @@ protected function setUp() $this->contextMock->expects($this->any()) ->method('getResultFactory') ->willReturn($this->resultFactoryMock); + $this->contextMock + ->method('getMessageManager') + ->willReturn($this->messageManager); } /** From 727ca8cb1a9ebc9d750c3409a0c6acb44a835482 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Fri, 14 Sep 2018 11:07:11 -0500 Subject: [PATCH 030/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Controller/Adminhtml/Product/Attribute/Save.php | 13 ++++++++++--- .../Adminhtml/Product/Attribute/Validate.php | 9 ++++++++- .../Adminhtml/Product/Attribute/Plugin/Save.php | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 0c6b2cb52e1a3..e32d84b393aeb 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -32,6 +32,8 @@ use Magento\Framework\View\Result\PageFactory; /** + * Product attribute save controller. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Save extends Attribute @@ -126,10 +128,13 @@ public function __construct( } /** + * @inheritdoc + * * @return Redirect * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @throws \Zend_Validate_Exception */ public function execute() { @@ -158,7 +163,7 @@ public function execute() $name = trim($name); try { - /** @var $attributeSet Set */ + /** @var Set $attributeSet */ $attributeSet = $this->buildFactory->create() ->setEntityTypeId($this->_entityTypeId) ->setSkeletonId($setId) @@ -180,7 +185,7 @@ public function execute() $attributeId = $this->getRequest()->getParam('attribute_id'); - /** @var $model ProductAttributeInterface */ + /** @var ProductAttributeInterface $model */ $model = $this->attributeFactory->create(); if ($attributeId) { $model->load($attributeId); @@ -212,7 +217,7 @@ public function execute() //validate frontend_input if (isset($data['frontend_input'])) { - /** @var $inputType Validator */ + /** @var Validator $inputType */ $inputType = $this->validatorFactory->create(); if (!$inputType->isValid($data['frontend_input'])) { foreach ($inputType->getMessages() as $message) { @@ -340,6 +345,8 @@ public function execute() } /** + * Provides an initialized Result object. + * * @param string $path * @param array $params * @param array $response diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index ca2ba9d231a33..34dcf6639f943 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -12,6 +12,8 @@ use Magento\Framework\DataObject; /** + * Product attribute validate controller. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute @@ -69,6 +71,8 @@ public function __construct( } /** + * @inheritdoc + * * @return \Magento\Framework\Controller\ResultInterface * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -146,7 +150,8 @@ public function execute() } /** - * Throws Exception if not unique values into options + * Throws Exception if not unique values into options. + * * @param array $optionsValues * @param array $deletedOptions * @return bool @@ -180,6 +185,8 @@ private function setMessageToResponse($response, $messages) } /** + * Performs checking the uniqueness of the attribute options. + * * @param DataObject $response * @param array|null $options * @return $this diff --git a/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php b/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php index 9ec65fb08045c..72d27152d639a 100644 --- a/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php +++ b/app/code/Magento/Swatches/Controller/Adminhtml/Product/Attribute/Plugin/Save.php @@ -16,6 +16,8 @@ class Save { /** + * Performs the conversion of the frontend input value. + * * @param Attribute\Save $subject * @param RequestInterface $request * @return array From 6dfd297fb804990486fd0d5b699cd8f9ddd20e71 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Fri, 14 Sep 2018 11:42:44 -0500 Subject: [PATCH 031/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Catalog/Controller/Adminhtml/Product/AttributeTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php index 4261873cc8e6e..ae8005db95a29 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php @@ -376,7 +376,8 @@ protected function _getAttributeData() 'used_in_product_listing' => '1', 'used_for_sort_by' => '0', 'apply_to' => ['simple'], - 'frontend_label' => [\Magento\Store\Model\Store::DEFAULT_STORE_ID => 'string to translate'] + 'frontend_label' => [\Magento\Store\Model\Store::DEFAULT_STORE_ID => 'string to translate'], + 'serialized_options' => '[]', ]; } } From 05665bbedcc25b9ac1d47083aee4ec647c2794fd Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Fri, 14 Sep 2018 14:27:33 -0500 Subject: [PATCH 032/118] MAGETWO-90540: MFTF Test failure - Advanced Reporting configuration permission --- .../Test/Mftf/Section/AdminConfigSection.xml | 2 +- .../Test/Mftf/Test/AdminConfigurationPermissionTest.xml | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) rename app/code/Magento/{Config => Analytics}/Test/Mftf/Section/AdminConfigSection.xml (93%) diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml b/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml similarity index 93% rename from app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml rename to app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml index dbede5491e011..9ec2c62a3c27a 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminConfigSection"> - <element name="advancedReportingMenuItem" type="text" selector="//a[contains(concat(' ',normalize-space(@class),' '),'item-nav')]/span[text()='Advanced Reporting']"/> + <element name="advancedReportingMenuItem" type="text" selector="//*[@id='system_config_tabs']/div[1]//span[text()='Advanced Reporting']"/> <element name="advancedReportingService" type="select" selector="#analytics_general_enabled"/> <element name="advancedReportingServiceLabel" type="text" selector="#row_analytics_general_enabled>td.label>label>span"/> <element name="advancedReportingServiceStatus" type="text" selector="#row_analytics_general_enabled>td.value>p>span"/> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml index d8aed1250d82a..5414e9c2a5c18 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml @@ -17,9 +17,6 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-82648"/> <group value="analytics"/> - <skip> - <issueId value="MAGETWO-90659"/> - </skip> </annotations> <before> <createData stepKey="noReportUserRole" entity="adminNoReportRole"/> From a3097e3394ed4015cbf47ac2abfb005d5702467d Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Fri, 14 Sep 2018 14:28:51 -0500 Subject: [PATCH 033/118] MAGETWO-90540: MFTF Test failure - Advanced Reporting configuration permission --- .../Test/Mftf/Section/AdminConfigSection.xml | 1 - .../Config/Test/Mftf/Section/AdminConfigSection.xml | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml diff --git a/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml b/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml index 9ec2c62a3c27a..f8554a4ea115b 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Section/AdminConfigSection.xml @@ -18,6 +18,5 @@ <element name="advancedReportingSeconds" type="select" selector="#row_analytics_general_collection_time>td:nth-child(2)>select:nth-child(4)"/> <element name="advancedReportingBlankIndustryError" type="text" selector=".message-error>div"/> <element name="advancedReportingSuccessMessage" type="text" selector=".message-success>div"/> - <element name="saveButton" type="button" selector="#save"/> </section> </sections> \ No newline at end of file diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml new file mode 100644 index 0000000000000..f4698b6865779 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminConfigSection"> + <element name="saveButton" type="button" selector="#save"/> + </section> +</sections> \ No newline at end of file From d83c61c9d84bf96d925915de881c210d066b2292 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Sun, 16 Sep 2018 19:38:15 -0500 Subject: [PATCH 034/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- ...ateVisualSwatchWithNonValidOptionsTest.xml | 2 +- dev/tests/acceptance/.gitignore | 1 + .../Handler/CatalogProductAttribute/Curl.php | 61 +++++++++++++++++++ .../Handler/SwatchProductAttribute/Curl.php | 4 +- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml index 92a33487615ea..1e9ce849db1be 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml @@ -17,7 +17,7 @@ <group value="Swatches"/> </annotations> <before> - <actionGroup ref="LoginActionGroup" stepKey="login"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> </before> <after> <!-- Remove attribute --> diff --git a/dev/tests/acceptance/.gitignore b/dev/tests/acceptance/.gitignore index e3ef78df82b9f..87ce9d4ff35d1 100755 --- a/dev/tests/acceptance/.gitignore +++ b/dev/tests/acceptance/.gitignore @@ -7,4 +7,5 @@ tests/functional.suite.yml tests/functional/Magento/FunctionalTest/_generated vendor/* mftf.log +/.credentials.example /utils/ \ No newline at end of file diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php index d78095f05fe45..57d775cdeb736 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductAttribute/Curl.php @@ -134,11 +134,72 @@ public function persist(FixtureInterface $fixture = null) } /** + * Additional data handling. + * * @param array $data * @return array */ protected function changeStructureOfTheData(array $data) { + $serializedOptions = $this->getSerializeOptions($data, ['option']); + if ($serializedOptions) { + $data['serialized_options'] = $serializedOptions; + unset($data['option']); + } + return $data; } + + /** + * Provides serialized product attribute options. + * + * @param array $data + * @param array $optionKeys + * @return array + */ + protected function getSerializeOptions(array $data, array $optionKeys): string + { + $options = []; + foreach ($optionKeys as $optionKey) { + if (!empty($data[$optionKey])) { + $options = array_merge( + $options, + $this->getEncodedOptions([$optionKey => $data[$optionKey]]) + ); + } + } + + return json_encode($options); + } + + /** + * Provides encoded attribute values. + * + * @param array $data + * @return array + */ + private function getEncodedOptions(array $data): array + { + $optionsData = []; + $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($data)); + foreach ($iterator as $value) { + $depth = $iterator->getDepth(); + $option = ''; + + $level = 0; + $option .= $iterator->getSubIterator($level)->key(); + $level++; + + while ($level <= $depth) { + $option .= '[' . $iterator->getSubIterator($level)->key() . ']'; + $level++; + } + + $option .= '=' . $value; + + $optionsData[] = $option; + } + + return $optionsData; + } } diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php index 083fa246c96ef..5e4a5cc45fe69 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php @@ -38,12 +38,14 @@ public function __construct(DataInterface $configuration, EventManagerInterface */ protected function changeStructureOfTheData(array $data) { - $data = parent::changeStructureOfTheData($data); $data['optiontext'] = $data['option']; $data['swatchtext'] = [ 'value' => $data['option']['value'] ]; + $data['serialized_options'] = $this->getSerializeOptions($data, ['optiontext', 'swatchtext']); unset($data['option']); + $data = parent::changeStructureOfTheData($data); + return $data; } } From ee0b4526d0afd75342279ec631b2703e09745f2b Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 17 Sep 2018 11:50:49 -0500 Subject: [PATCH 035/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fix functional tests --- app/code/Magento/Sales/Model/Order.php | 865 +++++++++++++++++-------- 1 file changed, 590 insertions(+), 275 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 89557be349953..47979591a5843 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -570,6 +570,7 @@ public function canCancel() /** * Getter whether the payment can be voided + * * @return bool */ public function canVoidPayment() @@ -886,7 +887,7 @@ protected function _placePayment() } /** - * {@inheritdoc} + * @inheritdoc */ public function getPayment() { @@ -1013,8 +1014,9 @@ public function addStatusToHistory($status, $comment = '', $isCustomerNotified = } /** - * Add a comment to order - * Different or default status may be specified + * Add a comment to order. + * + * Different or default status may be specified. * * @param string $comment * @param bool|string $status @@ -1028,8 +1030,9 @@ public function addStatusHistoryComment($comment, $status = false) } /** - * Add a comment to order status history - * Different or default status may be specified + * Add a comment to order status history. + * + * Different or default status may be specified. * * @param string $comment * @param bool|string $status @@ -1094,6 +1097,8 @@ public function place() } /** + * Hold + * * @return $this * @throws \Magento\Framework\Exception\LocalizedException */ @@ -1239,6 +1244,8 @@ public function getShippingMethod($asObject = false) /*********************** ADDRESSES ***************************/ /** + * Get addresses collection + * * @return Collection */ public function getAddressesCollection() @@ -1253,6 +1260,8 @@ public function getAddressesCollection() } /** + * Get address by id + * * @param mixed $addressId * @return false */ @@ -1267,6 +1276,8 @@ public function getAddressById($addressId) } /** + * Add address + * * @param \Magento\Sales\Model\Order\Address $address * @return $this */ @@ -1281,6 +1292,8 @@ public function addAddress(\Magento\Sales\Model\Order\Address $address) } /** + * Get items collection + * * @param array $filterByTypes * @param bool $nonChildrenOnly * @return ImportCollection @@ -1353,6 +1366,8 @@ protected function _getItemsRandomCollection($limit, $nonChildrenOnly = false) } /** + * Get all items + * * @return \Magento\Sales\Model\Order\Item[] */ public function getAllItems() @@ -1367,6 +1382,8 @@ public function getAllItems() } /** + * Get all visible items + * * @return array */ public function getAllVisibleItems() @@ -1398,6 +1415,8 @@ public function getItemById($itemId) } /** + * Get item by quote item id + * * @param mixed $quoteItemId * @return \Magento\Framework\DataObject|null */ @@ -1412,6 +1431,8 @@ public function getItemByQuoteItemId($quoteItemId) } /** + * Add item + * * @param \Magento\Sales\Model\Order\Item $item * @return $this */ @@ -1427,6 +1448,8 @@ public function addItem(\Magento\Sales\Model\Order\Item $item) /*********************** PAYMENTS ***************************/ /** + * Get payments collection + * * @return PaymentCollection */ public function getPaymentsCollection() @@ -1441,6 +1464,8 @@ public function getPaymentsCollection() } /** + * Get all payments + * * @return array */ public function getAllPayments() @@ -1455,6 +1480,8 @@ public function getAllPayments() } /** + * Get payment by id + * * @param mixed $paymentId * @return Payment|false */ @@ -1469,7 +1496,9 @@ public function getPaymentById($paymentId) } /** - * {@inheritdoc} + * Set payment + * + * @return \Magento\Sales\Api\Data\OrderPaymentInterface|null */ public function setPayment(\Magento\Sales\Api\Data\OrderPaymentInterface $payment = null) { @@ -1536,6 +1565,8 @@ public function getVisibleStatusHistory() } /** + * GetStatus history by id + * * @param mixed $statusId * @return string|false */ @@ -1550,7 +1581,8 @@ public function getStatusHistoryById($statusId) } /** - * Set the order status history object and the order object to each other + * Set the order status history object and the order object to each other. + * * Adds the object to the status history collection, which is automatically saved when the order is saved. * See the entity_id attribute backend model. * Or the history record can be saved standalone after this. @@ -1570,6 +1602,8 @@ public function addStatusHistory(\Magento\Sales\Model\Order\Status\History $hist } /** + * Get real real_order_id + * * @return string */ public function getRealOrderId() @@ -1608,6 +1642,8 @@ public function formatPrice($price, $addBrackets = false) } /** + * Format price precision + * * @param float $price * @param int $precision * @param bool $addBrackets @@ -1643,6 +1679,8 @@ public function getBaseCurrency() } /** + * Format BasePrice + * * @param float $price * @return string */ @@ -1652,6 +1690,8 @@ public function formatBasePrice($price) } /** + * Format BasePrice Precision + * * @param float $price * @param int $precision * @return string @@ -1662,6 +1702,8 @@ public function formatBasePricePrecision($price, $precision) } /** + * Is currency different + * * @return bool */ public function isCurrencyDifferent() @@ -1694,6 +1736,8 @@ public function getBaseTotalDue() } /** + * Get data + * * @param string $key * @param null|string|int $index * @return mixed @@ -1861,8 +1905,8 @@ public function addRelatedObject(\Magento\Framework\Model\AbstractModel $object) /** * Get formatted order created date in store timezone * - * @param string $format date format type (short|medium|long|full) - * @return string + * @param string $format date format type (short|medium|long|full) + * @return string */ public function getCreatedAtFormatted($format) { @@ -1876,6 +1920,8 @@ public function getCreatedAtFormatted($format) } /** + * Get email customer note + * * @return string */ public function getEmailCustomerNote() @@ -1887,6 +1933,8 @@ public function getEmailCustomerNote() } /** + * Get store group name + * * @return string */ public function getStoreGroupName() @@ -1899,8 +1947,7 @@ public function getStoreGroupName() } /** - * Resets all data in object - * so after another load it will be complete new object + * Reset all data in object so after another load it will be complete new object. * * @return $this */ @@ -1924,6 +1971,8 @@ public function reset() } /** + * Get IsNotVirtual + * * @return bool * @SuppressWarnings(PHPMD.BooleanGetMethodName) */ @@ -1954,7 +2003,7 @@ public function isCanceled() } /** - * Returns increment id + * Return increment id * * @codeCoverageIgnore * @@ -1966,6 +2015,8 @@ public function getIncrementId() } /** + * Get Items + * * @return \Magento\Sales\Api\Data\OrderItemInterface[] */ public function getItems() @@ -1980,7 +2031,9 @@ public function getItems() } /** - * {@inheritdoc} + * Set Items + * + * @return $this * @codeCoverageIgnore */ public function setItems($items) @@ -1989,6 +2042,8 @@ public function setItems($items) } /** + * Get addresses + * * @return \Magento\Sales\Api\Data\OrderAddressInterface[] */ public function getAddresses() @@ -2003,6 +2058,8 @@ public function getAddresses() } /** + * Get status History + * * @return \Magento\Sales\Api\Data\OrderStatusHistoryInterface[]|null */ public function getStatusHistories() @@ -2017,7 +2074,7 @@ public function getStatusHistories() } /** - * {@inheritdoc} + * Get ExtensionAttributes * * @return \Magento\Sales\Api\Data\OrderExtensionInterface|null */ @@ -2027,7 +2084,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * Set ExtensionAttributes * * @param \Magento\Sales\Api\Data\OrderExtensionInterface $extensionAttributes * @return $this @@ -2040,7 +2097,7 @@ public function setExtensionAttributes(\Magento\Sales\Api\Data\OrderExtensionInt //@codeCoverageIgnoreStart /** - * Returns adjustment_negative + * Return adjustment_negative * * @return float|null */ @@ -2050,7 +2107,7 @@ public function getAdjustmentNegative() } /** - * Returns adjustment_positive + * Return adjustment_positive * * @return float|null */ @@ -2060,7 +2117,7 @@ public function getAdjustmentPositive() } /** - * Returns applied_rule_ids + * Return applied_rule_ids * * @return string|null */ @@ -2070,7 +2127,7 @@ public function getAppliedRuleIds() } /** - * Returns base_adjustment_negative + * Return base_adjustment_negative * * @return float|null */ @@ -2080,7 +2137,7 @@ public function getBaseAdjustmentNegative() } /** - * Returns base_adjustment_positive + * Return base_adjustment_positive * * @return float|null */ @@ -2090,7 +2147,7 @@ public function getBaseAdjustmentPositive() } /** - * Returns base_currency_code + * Return base_currency_code * * @return string|null */ @@ -2100,7 +2157,7 @@ public function getBaseCurrencyCode() } /** - * Returns base_discount_amount + * Return base_discount_amount * * @return float|null */ @@ -2110,7 +2167,7 @@ public function getBaseDiscountAmount() } /** - * Returns base_discount_canceled + * Return base_discount_canceled * * @return float|null */ @@ -2120,7 +2177,7 @@ public function getBaseDiscountCanceled() } /** - * Returns base_discount_invoiced + * Return base_discount_invoiced * * @return float|null */ @@ -2130,7 +2187,7 @@ public function getBaseDiscountInvoiced() } /** - * Returns base_discount_refunded + * Return base_discount_refunded * * @return float|null */ @@ -2140,7 +2197,7 @@ public function getBaseDiscountRefunded() } /** - * Returns base_grand_total + * Return base_grand_total * * @return float */ @@ -2150,7 +2207,7 @@ public function getBaseGrandTotal() } /** - * Returns base_discount_tax_compensation_amount + * Return base_discount_tax_compensation_amount * * @return float|null */ @@ -2160,7 +2217,7 @@ public function getBaseDiscountTaxCompensationAmount() } /** - * Returns base_discount_tax_compensation_invoiced + * Return base_discount_tax_compensation_invoiced * * @return float|null */ @@ -2170,7 +2227,7 @@ public function getBaseDiscountTaxCompensationInvoiced() } /** - * Returns base_discount_tax_compensation_refunded + * Return base_discount_tax_compensation_refunded * * @return float|null */ @@ -2180,7 +2237,7 @@ public function getBaseDiscountTaxCompensationRefunded() } /** - * Returns base_shipping_amount + * Return base_shipping_amount * * @return float|null */ @@ -2190,7 +2247,7 @@ public function getBaseShippingAmount() } /** - * Returns base_shipping_canceled + * Return base_shipping_canceled * * @return float|null */ @@ -2200,7 +2257,7 @@ public function getBaseShippingCanceled() } /** - * Returns base_shipping_discount_amount + * Return base_shipping_discount_amount * * @return float|null */ @@ -2210,7 +2267,7 @@ public function getBaseShippingDiscountAmount() } /** - * Returns base_shipping_discount_tax_compensation_amnt + * Return base_shipping_discount_tax_compensation_amnt * * @return float|null */ @@ -2220,7 +2277,7 @@ public function getBaseShippingDiscountTaxCompensationAmnt() } /** - * Returns base_shipping_incl_tax + * Return base_shipping_incl_tax * * @return float|null */ @@ -2230,8 +2287,8 @@ public function getBaseShippingInclTax() } /** - * Returns base_shipping_invoiced - * + * Return base_shipping_invoiced + * @return float|null */ public function getBaseShippingInvoiced() @@ -2240,7 +2297,7 @@ public function getBaseShippingInvoiced() } /** - * Returns base_shipping_refunded + * Return base_shipping_refunded * * @return float|null */ @@ -2250,7 +2307,7 @@ public function getBaseShippingRefunded() } /** - * Returns base_shipping_tax_amount + * Return base_shipping_tax_amount * * @return float|null */ @@ -2260,7 +2317,7 @@ public function getBaseShippingTaxAmount() } /** - * Returns base_shipping_tax_refunded + * Return base_shipping_tax_refunded * * @return float|null */ @@ -2270,7 +2327,7 @@ public function getBaseShippingTaxRefunded() } /** - * Returns base_subtotal + * Return base_subtotal * * @return float|null */ @@ -2280,7 +2337,7 @@ public function getBaseSubtotal() } /** - * Returns base_subtotal_canceled + * Return base_subtotal_canceled * * @return float|null */ @@ -2290,7 +2347,7 @@ public function getBaseSubtotalCanceled() } /** - * Returns base_subtotal_incl_tax + * Return base_subtotal_incl_tax * * @return float|null */ @@ -2300,7 +2357,7 @@ public function getBaseSubtotalInclTax() } /** - * Returns base_subtotal_invoiced + * Return base_subtotal_invoiced * * @return float|null */ @@ -2310,7 +2367,7 @@ public function getBaseSubtotalInvoiced() } /** - * Returns base_subtotal_refunded + * Return base_subtotal_refunded * * @return float|null */ @@ -2320,7 +2377,7 @@ public function getBaseSubtotalRefunded() } /** - * Returns base_tax_amount + * Return base_tax_amount * * @return float|null */ @@ -2330,7 +2387,7 @@ public function getBaseTaxAmount() } /** - * Returns base_tax_canceled + * Return base_tax_canceled * * @return float|null */ @@ -2340,7 +2397,7 @@ public function getBaseTaxCanceled() } /** - * Returns base_tax_invoiced + * Return base_tax_invoiced * * @return float|null */ @@ -2350,7 +2407,7 @@ public function getBaseTaxInvoiced() } /** - * Returns base_tax_refunded + * Return base_tax_refunded * * @return float|null */ @@ -2360,7 +2417,7 @@ public function getBaseTaxRefunded() } /** - * Returns base_total_canceled + * Return base_total_canceled * * @return float|null */ @@ -2370,7 +2427,7 @@ public function getBaseTotalCanceled() } /** - * Returns base_total_invoiced + * Return base_total_invoiced * * @return float|null */ @@ -2380,7 +2437,7 @@ public function getBaseTotalInvoiced() } /** - * Returns base_total_invoiced_cost + * Return base_total_invoiced_cost * * @return float|null */ @@ -2390,7 +2447,7 @@ public function getBaseTotalInvoicedCost() } /** - * Returns base_total_offline_refunded + * Return base_total_offline_refunded * * @return float|null */ @@ -2400,7 +2457,7 @@ public function getBaseTotalOfflineRefunded() } /** - * Returns base_total_online_refunded + * Return base_total_online_refunded * * @return float|null */ @@ -2410,7 +2467,7 @@ public function getBaseTotalOnlineRefunded() } /** - * Returns base_total_paid + * Return base_total_paid * * @return float|null */ @@ -2420,7 +2477,7 @@ public function getBaseTotalPaid() } /** - * Returns base_total_qty_ordered + * Return base_total_qty_ordered * * @return float|null */ @@ -2430,7 +2487,7 @@ public function getBaseTotalQtyOrdered() } /** - * Returns base_total_refunded + * Return base_total_refunded * * @return float|null */ @@ -2440,7 +2497,7 @@ public function getBaseTotalRefunded() } /** - * Returns base_to_global_rate + * Return base_to_global_rate * * @return float|null */ @@ -2450,7 +2507,7 @@ public function getBaseToGlobalRate() } /** - * Returns base_to_order_rate + * Return base_to_order_rate * * @return float|null */ @@ -2460,7 +2517,7 @@ public function getBaseToOrderRate() } /** - * Returns billing_address_id + * Return billing_address_id * * @return int|null */ @@ -2470,7 +2527,7 @@ public function getBillingAddressId() } /** - * Returns can_ship_partially + * Return can_ship_partially * * @return int|null */ @@ -2480,7 +2537,7 @@ public function getCanShipPartially() } /** - * Returns can_ship_partially_item + * Return can_ship_partially_item * * @return int|null */ @@ -2490,7 +2547,7 @@ public function getCanShipPartiallyItem() } /** - * Returns coupon_code + * Return coupon_code * * @return string|null */ @@ -2500,7 +2557,7 @@ public function getCouponCode() } /** - * Returns created_at + * Return created_at * * @return string|null */ @@ -2510,7 +2567,7 @@ public function getCreatedAt() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCreatedAt($createdAt) { @@ -2518,7 +2575,7 @@ public function setCreatedAt($createdAt) } /** - * Returns customer_dob + * Return customer_dob * * @return string|null */ @@ -2528,7 +2585,7 @@ public function getCustomerDob() } /** - * Returns customer_email + * Return customer_email * * @return string */ @@ -2538,7 +2595,7 @@ public function getCustomerEmail() } /** - * Returns customer_firstname + * Return customer_firstname * * @return string|null */ @@ -2548,7 +2605,7 @@ public function getCustomerFirstname() } /** - * Returns customer_gender + * Return customer_gender * * @return int|null */ @@ -2558,7 +2615,7 @@ public function getCustomerGender() } /** - * Returns customer_group_id + * Return customer_group_id * * @return int|null */ @@ -2568,7 +2625,7 @@ public function getCustomerGroupId() } /** - * Returns customer_id + * Return customer_id * * @return int|null */ @@ -2578,7 +2635,7 @@ public function getCustomerId() } /** - * Returns customer_is_guest + * Return customer_is_guest * * @return int|null */ @@ -2588,7 +2645,7 @@ public function getCustomerIsGuest() } /** - * Returns customer_lastname + * Return customer_lastname * * @return string|null */ @@ -2598,7 +2655,7 @@ public function getCustomerLastname() } /** - * Returns customer_middlename + * Return customer_middlename * * @return string|null */ @@ -2608,7 +2665,7 @@ public function getCustomerMiddlename() } /** - * Returns customer_note + * Return customer_note * * @return string|null */ @@ -2618,7 +2675,7 @@ public function getCustomerNote() } /** - * Returns customer_note_notify + * Return customer_note_notify * * @return int|null */ @@ -2628,7 +2685,7 @@ public function getCustomerNoteNotify() } /** - * Returns customer_prefix + * Return customer_prefix * * @return string|null */ @@ -2638,7 +2695,7 @@ public function getCustomerPrefix() } /** - * Returns customer_suffix + * Return customer_suffix * * @return string|null */ @@ -2648,7 +2705,7 @@ public function getCustomerSuffix() } /** - * Returns customer_taxvat + * Return customer_taxvat * * @return string|null */ @@ -2658,7 +2715,7 @@ public function getCustomerTaxvat() } /** - * Returns discount_amount + * Return discount_amount * * @return float|null */ @@ -2668,7 +2725,7 @@ public function getDiscountAmount() } /** - * Returns discount_canceled + * Return discount_canceled * * @return float|null */ @@ -2678,7 +2735,7 @@ public function getDiscountCanceled() } /** - * Returns discount_description + * Return discount_description * * @return string|null */ @@ -2688,7 +2745,7 @@ public function getDiscountDescription() } /** - * Returns discount_invoiced + * Return discount_invoiced * * @return float|null */ @@ -2698,7 +2755,7 @@ public function getDiscountInvoiced() } /** - * Returns discount_refunded + * Return discount_refunded * * @return float|null */ @@ -2708,7 +2765,7 @@ public function getDiscountRefunded() } /** - * Returns edit_increment + * Return edit_increment * * @return int|null */ @@ -2718,7 +2775,7 @@ public function getEditIncrement() } /** - * Returns email_sent + * Return email_sent * * @return int|null */ @@ -2728,7 +2785,7 @@ public function getEmailSent() } /** - * Returns ext_customer_id + * Return ext_customer_id * * @return string|null */ @@ -2738,7 +2795,7 @@ public function getExtCustomerId() } /** - * Returns ext_order_id + * Return ext_order_id * * @return string|null */ @@ -2748,7 +2805,7 @@ public function getExtOrderId() } /** - * Returns forced_shipment_with_invoice + * Return forced_shipment_with_invoice * * @return int|null */ @@ -2758,7 +2815,7 @@ public function getForcedShipmentWithInvoice() } /** - * Returns global_currency_code + * Return global_currency_code * * @return string|null */ @@ -2768,7 +2825,7 @@ public function getGlobalCurrencyCode() } /** - * Returns grand_total + * Return grand_total * * @return float */ @@ -2778,7 +2835,7 @@ public function getGrandTotal() } /** - * Returns discount_tax_compensation_amount + * Return discount_tax_compensation_amount * * @return float|null */ @@ -2788,7 +2845,7 @@ public function getDiscountTaxCompensationAmount() } /** - * Returns discount_tax_compensation_invoiced + * Return discount_tax_compensation_invoiced * * @return float|null */ @@ -2798,7 +2855,7 @@ public function getDiscountTaxCompensationInvoiced() } /** - * Returns discount_tax_compensation_refunded + * Return discount_tax_compensation_refunded * * @return float|null */ @@ -2808,7 +2865,7 @@ public function getDiscountTaxCompensationRefunded() } /** - * Returns hold_before_state + * Return hold_before_state * * @return string|null */ @@ -2818,7 +2875,7 @@ public function getHoldBeforeState() } /** - * Returns hold_before_status + * Return hold_before_status * * @return string|null */ @@ -2828,7 +2885,7 @@ public function getHoldBeforeStatus() } /** - * Returns is_virtual + * Return is_virtual * * @return int|null */ @@ -2838,7 +2895,7 @@ public function getIsVirtual() } /** - * Returns order_currency_code + * Return order_currency_code * * @return string|null */ @@ -2848,7 +2905,7 @@ public function getOrderCurrencyCode() } /** - * Returns original_increment_id + * Return original_increment_id * * @return string|null */ @@ -2858,7 +2915,7 @@ public function getOriginalIncrementId() } /** - * Returns payment_authorization_amount + * Return payment_authorization_amount * * @return float|null */ @@ -2868,7 +2925,7 @@ public function getPaymentAuthorizationAmount() } /** - * Returns payment_auth_expiration + * Return payment_auth_expiration * * @return int|null */ @@ -2878,7 +2935,7 @@ public function getPaymentAuthExpiration() } /** - * Returns protect_code + * Return protect_code * * @return string|null */ @@ -2888,7 +2945,7 @@ public function getProtectCode() } /** - * Returns quote_address_id + * Return quote_address_id * * @return int|null */ @@ -2898,7 +2955,7 @@ public function getQuoteAddressId() } /** - * Returns quote_id + * Return quote_id * * @return int|null */ @@ -2908,7 +2965,7 @@ public function getQuoteId() } /** - * Returns relation_child_id + * Return relation_child_id * * @return string|null */ @@ -2918,7 +2975,7 @@ public function getRelationChildId() } /** - * Returns relation_child_real_id + * Return relation_child_real_id * * @return string|null */ @@ -2928,7 +2985,7 @@ public function getRelationChildRealId() } /** - * Returns relation_parent_id + * Return relation_parent_id * * @return string|null */ @@ -2938,7 +2995,7 @@ public function getRelationParentId() } /** - * Returns relation_parent_real_id + * Return relation_parent_real_id * * @return string|null */ @@ -2948,7 +3005,7 @@ public function getRelationParentRealId() } /** - * Returns remote_ip + * Return remote_ip * * @return string|null */ @@ -2958,7 +3015,7 @@ public function getRemoteIp() } /** - * Returns shipping_amount + * Return shipping_amount * * @return float|null */ @@ -2968,7 +3025,7 @@ public function getShippingAmount() } /** - * Returns shipping_canceled + * Return shipping_canceled * * @return float|null */ @@ -2978,7 +3035,7 @@ public function getShippingCanceled() } /** - * Returns shipping_description + * Return shipping_description * * @return string|null */ @@ -2988,7 +3045,7 @@ public function getShippingDescription() } /** - * Returns shipping_discount_amount + * Return shipping_discount_amount * * @return float|null */ @@ -2998,7 +3055,7 @@ public function getShippingDiscountAmount() } /** - * Returns shipping_discount_tax_compensation_amount + * Return shipping_discount_tax_compensation_amount * * @return float|null */ @@ -3008,7 +3065,7 @@ public function getShippingDiscountTaxCompensationAmount() } /** - * Returns shipping_incl_tax + * Return shipping_incl_tax * * @return float|null */ @@ -3018,7 +3075,7 @@ public function getShippingInclTax() } /** - * Returns shipping_invoiced + * Return shipping_invoiced * * @return float|null */ @@ -3028,7 +3085,7 @@ public function getShippingInvoiced() } /** - * Returns shipping_refunded + * Return shipping_refunded * * @return float|null */ @@ -3038,7 +3095,7 @@ public function getShippingRefunded() } /** - * Returns shipping_tax_amount + * Return shipping_tax_amount * * @return float|null */ @@ -3048,7 +3105,7 @@ public function getShippingTaxAmount() } /** - * Returns shipping_tax_refunded + * Return shipping_tax_refunded * * @return float|null */ @@ -3058,7 +3115,7 @@ public function getShippingTaxRefunded() } /** - * Returns state + * Return state * * @return string|null */ @@ -3068,7 +3125,7 @@ public function getState() } /** - * Returns status + * Return status * * @return string|null */ @@ -3078,7 +3135,7 @@ public function getStatus() } /** - * Returns store_currency_code + * Return store_currency_code * * @return string|null */ @@ -3088,7 +3145,7 @@ public function getStoreCurrencyCode() } /** - * Returns store_id + * Return store_id * * @return int|null */ @@ -3098,7 +3155,7 @@ public function getStoreId() } /** - * Returns store_name + * Return store_name * * @return string|null */ @@ -3108,7 +3165,7 @@ public function getStoreName() } /** - * Returns store_to_base_rate + * Return store_to_base_rate * * @return float|null */ @@ -3118,7 +3175,7 @@ public function getStoreToBaseRate() } /** - * Returns store_to_order_rate + * Return store_to_order_rate * * @return float|null */ @@ -3128,7 +3185,7 @@ public function getStoreToOrderRate() } /** - * Returns subtotal + * Return subtotal * * @return float|null */ @@ -3138,7 +3195,7 @@ public function getSubtotal() } /** - * Returns subtotal_canceled + * Return subtotal_canceled * * @return float|null */ @@ -3148,7 +3205,7 @@ public function getSubtotalCanceled() } /** - * Returns subtotal_incl_tax + * Return subtotal_incl_tax * * @return float|null */ @@ -3158,7 +3215,7 @@ public function getSubtotalInclTax() } /** - * Returns subtotal_invoiced + * Return subtotal_invoiced * * @return float|null */ @@ -3168,7 +3225,7 @@ public function getSubtotalInvoiced() } /** - * Returns subtotal_refunded + * Return subtotal_refunded * * @return float|null */ @@ -3178,7 +3235,7 @@ public function getSubtotalRefunded() } /** - * Returns tax_amount + * Return tax_amount * * @return float|null */ @@ -3188,7 +3245,7 @@ public function getTaxAmount() } /** - * Returns tax_canceled + * Return tax_canceled * * @return float|null */ @@ -3198,7 +3255,7 @@ public function getTaxCanceled() } /** - * Returns tax_invoiced + * Return tax_invoiced * * @return float|null */ @@ -3208,7 +3265,7 @@ public function getTaxInvoiced() } /** - * Returns tax_refunded + * Return tax_refunded * * @return float|null */ @@ -3218,7 +3275,7 @@ public function getTaxRefunded() } /** - * Returns total_canceled + * Return total_canceled * * @return float|null */ @@ -3228,7 +3285,7 @@ public function getTotalCanceled() } /** - * Returns total_invoiced + * Return total_invoiced * * @return float|null */ @@ -3238,7 +3295,7 @@ public function getTotalInvoiced() } /** - * Returns total_item_count + * Return total_item_count * * @return int|null */ @@ -3248,7 +3305,7 @@ public function getTotalItemCount() } /** - * Returns total_offline_refunded + * Return total_offline_refunded * * @return float|null */ @@ -3258,7 +3315,7 @@ public function getTotalOfflineRefunded() } /** - * Returns total_online_refunded + * Return total_online_refunded * * @return float|null */ @@ -3268,7 +3325,7 @@ public function getTotalOnlineRefunded() } /** - * Returns total_paid + * Return total_paid * * @return float|null */ @@ -3278,7 +3335,7 @@ public function getTotalPaid() } /** - * Returns total_qty_ordered + * Return total_qty_ordered * * @return float|null */ @@ -3288,7 +3345,7 @@ public function getTotalQtyOrdered() } /** - * Returns total_refunded + * Return total_refunded * * @return float|null */ @@ -3298,7 +3355,7 @@ public function getTotalRefunded() } /** - * Returns updated_at + * Return updated_at * * @return string|null */ @@ -3308,7 +3365,7 @@ public function getUpdatedAt() } /** - * Returns weight + * Return weight * * @return float|null */ @@ -3318,7 +3375,7 @@ public function getWeight() } /** - * Returns x_forwarded_for + * Return x_forwarded_for * * @return string|null */ @@ -3328,7 +3385,9 @@ public function getXForwardedFor() } /** - * {@inheritdoc} + * Set StatusHistories + * + * @return $this */ public function setStatusHistories(array $statusHistories = null) { @@ -3336,7 +3395,9 @@ public function setStatusHistories(array $statusHistories = null) } /** - * {@inheritdoc} + * Set Status + * + * @return $this */ public function setStatus($status) { @@ -3344,7 +3405,9 @@ public function setStatus($status) } /** - * {@inheritdoc} + * Set CouponCode + * + * @return $this */ public function setCouponCode($code) { @@ -3352,7 +3415,9 @@ public function setCouponCode($code) } /** - * {@inheritdoc} + * Set ProtectCode + * + * @return $this */ public function setProtectCode($code) { @@ -3360,7 +3425,9 @@ public function setProtectCode($code) } /** - * {@inheritdoc} + * Set ShippingDescription + * + * @return $this */ public function setShippingDescription($description) { @@ -3368,7 +3435,9 @@ public function setShippingDescription($description) } /** - * {@inheritdoc} + * Set IsVirtual + * + * @return $this */ public function setIsVirtual($isVirtual) { @@ -3376,7 +3445,9 @@ public function setIsVirtual($isVirtual) } /** - * {@inheritdoc} + * Set StoreId + * + * @return $this */ public function setStoreId($id) { @@ -3384,7 +3455,9 @@ public function setStoreId($id) } /** - * {@inheritdoc} + * Set CustomerId + * + * @return $this */ public function setCustomerId($id) { @@ -3392,7 +3465,9 @@ public function setCustomerId($id) } /** - * {@inheritdoc} + * Set BaseDiscountAmount + * + * @return $this */ public function setBaseDiscountAmount($amount) { @@ -3400,7 +3475,9 @@ public function setBaseDiscountAmount($amount) } /** - * {@inheritdoc} + * Set BaseDiscountCanceled + * + * @return $this */ public function setBaseDiscountCanceled($baseDiscountCanceled) { @@ -3408,7 +3485,9 @@ public function setBaseDiscountCanceled($baseDiscountCanceled) } /** - * {@inheritdoc} + * Set BaseDiscountInvoiced + * + * @return $this */ public function setBaseDiscountInvoiced($baseDiscountInvoiced) { @@ -3416,7 +3495,9 @@ public function setBaseDiscountInvoiced($baseDiscountInvoiced) } /** - * {@inheritdoc} + * Set BaseDiscountRefunded + * + * @return $this */ public function setBaseDiscountRefunded($baseDiscountRefunded) { @@ -3424,7 +3505,9 @@ public function setBaseDiscountRefunded($baseDiscountRefunded) } /** - * {@inheritdoc} + * Set BaseGrandTotal + * + * @return $this */ public function setBaseGrandTotal($amount) { @@ -3432,7 +3515,9 @@ public function setBaseGrandTotal($amount) } /** - * {@inheritdoc} + * Set BaseShippingAmount + * + * @return $this */ public function setBaseShippingAmount($amount) { @@ -3440,7 +3525,9 @@ public function setBaseShippingAmount($amount) } /** - * {@inheritdoc} + * Set BaseShippingCanceled + * + * @return $this */ public function setBaseShippingCanceled($baseShippingCanceled) { @@ -3448,7 +3535,9 @@ public function setBaseShippingCanceled($baseShippingCanceled) } /** - * {@inheritdoc} + * Set BaseShippingInvoiced + * + * @return $this */ public function setBaseShippingInvoiced($baseShippingInvoiced) { @@ -3456,7 +3545,9 @@ public function setBaseShippingInvoiced($baseShippingInvoiced) } /** - * {@inheritdoc} + * Set BaseShippingRefunded + * + * @return $this */ public function setBaseShippingRefunded($baseShippingRefunded) { @@ -3464,7 +3555,9 @@ public function setBaseShippingRefunded($baseShippingRefunded) } /** - * {@inheritdoc} + * Set BaseShippingTaxAmount + * + * @return $this */ public function setBaseShippingTaxAmount($amount) { @@ -3472,7 +3565,9 @@ public function setBaseShippingTaxAmount($amount) } /** - * {@inheritdoc} + * Set BaseShippingTaxRefunded + * + * @return $this */ public function setBaseShippingTaxRefunded($baseShippingTaxRefunded) { @@ -3480,7 +3575,9 @@ public function setBaseShippingTaxRefunded($baseShippingTaxRefunded) } /** - * {@inheritdoc} + * Set BaseSubtotal + * + * @return $this */ public function setBaseSubtotal($amount) { @@ -3488,7 +3585,9 @@ public function setBaseSubtotal($amount) } /** - * {@inheritdoc} + * Set BaseSubtotalCanceled + * + * @return $this */ public function setBaseSubtotalCanceled($baseSubtotalCanceled) { @@ -3496,7 +3595,9 @@ public function setBaseSubtotalCanceled($baseSubtotalCanceled) } /** - * {@inheritdoc} + * Set BaseSubtotalInvoiced + * + * @return $this */ public function setBaseSubtotalInvoiced($baseSubtotalInvoiced) { @@ -3504,7 +3605,9 @@ public function setBaseSubtotalInvoiced($baseSubtotalInvoiced) } /** - * {@inheritdoc} + * Set BaseSubtotalRefunded + * + * @return $this */ public function setBaseSubtotalRefunded($baseSubtotalRefunded) { @@ -3512,7 +3615,9 @@ public function setBaseSubtotalRefunded($baseSubtotalRefunded) } /** - * {@inheritdoc} + * Set BaseTaxAmount + * + * @return $this */ public function setBaseTaxAmount($amount) { @@ -3520,7 +3625,9 @@ public function setBaseTaxAmount($amount) } /** - * {@inheritdoc} + * Set BaseTaxCanceled + * + * @return $this */ public function setBaseTaxCanceled($baseTaxCanceled) { @@ -3528,7 +3635,9 @@ public function setBaseTaxCanceled($baseTaxCanceled) } /** - * {@inheritdoc} + * Set BaseTaxInvoiced + * + * @return $this */ public function setBaseTaxInvoiced($baseTaxInvoiced) { @@ -3536,7 +3645,9 @@ public function setBaseTaxInvoiced($baseTaxInvoiced) } /** - * {@inheritdoc} + * Set BaseTaxRefunded + * + * @return $this */ public function setBaseTaxRefunded($baseTaxRefunded) { @@ -3544,7 +3655,9 @@ public function setBaseTaxRefunded($baseTaxRefunded) } /** - * {@inheritdoc} + * Set BaseToGlobalRate + * + * @return $this */ public function setBaseToGlobalRate($rate) { @@ -3552,7 +3665,9 @@ public function setBaseToGlobalRate($rate) } /** - * {@inheritdoc} + * Set BaseToOrderRate + * + * @return $this */ public function setBaseToOrderRate($rate) { @@ -3560,7 +3675,9 @@ public function setBaseToOrderRate($rate) } /** - * {@inheritdoc} + * Set BaseTotalCanceled + * + * @return $this */ public function setBaseTotalCanceled($baseTotalCanceled) { @@ -3568,7 +3685,9 @@ public function setBaseTotalCanceled($baseTotalCanceled) } /** - * {@inheritdoc} + * Set BaseTotalInvoiced + * + * @return $this */ public function setBaseTotalInvoiced($baseTotalInvoiced) { @@ -3576,7 +3695,9 @@ public function setBaseTotalInvoiced($baseTotalInvoiced) } /** - * {@inheritdoc} + * Set BaseTotalInvoicedCost + * + * @return $this */ public function setBaseTotalInvoicedCost($baseTotalInvoicedCost) { @@ -3584,7 +3705,9 @@ public function setBaseTotalInvoicedCost($baseTotalInvoicedCost) } /** - * {@inheritdoc} + * Set BaseTotalOfflineRefunded + * + * @return $this */ public function setBaseTotalOfflineRefunded($baseTotalOfflineRefunded) { @@ -3592,7 +3715,9 @@ public function setBaseTotalOfflineRefunded($baseTotalOfflineRefunded) } /** - * {@inheritdoc} + * Set BaseTotalOnlineRefunded + * + * @return $this */ public function setBaseTotalOnlineRefunded($baseTotalOnlineRefunded) { @@ -3600,7 +3725,9 @@ public function setBaseTotalOnlineRefunded($baseTotalOnlineRefunded) } /** - * {@inheritdoc} + * Set BaseTotalPaid + * + * @return $this */ public function setBaseTotalPaid($baseTotalPaid) { @@ -3608,7 +3735,9 @@ public function setBaseTotalPaid($baseTotalPaid) } /** - * {@inheritdoc} + * Set BaseTotalQtyOrdered + * + * @return $this */ public function setBaseTotalQtyOrdered($baseTotalQtyOrdered) { @@ -3616,7 +3745,9 @@ public function setBaseTotalQtyOrdered($baseTotalQtyOrdered) } /** - * {@inheritdoc} + * Set BaseTotalRefunded + * + * @return $this */ public function setBaseTotalRefunded($baseTotalRefunded) { @@ -3624,7 +3755,9 @@ public function setBaseTotalRefunded($baseTotalRefunded) } /** - * {@inheritdoc} + * Set DiscountAmount + * + * @return $this */ public function setDiscountAmount($amount) { @@ -3632,7 +3765,9 @@ public function setDiscountAmount($amount) } /** - * {@inheritdoc} + * Set DiscountCanceled + * + * @return $this */ public function setDiscountCanceled($discountCanceled) { @@ -3640,7 +3775,9 @@ public function setDiscountCanceled($discountCanceled) } /** - * {@inheritdoc} + * Set DiscountInvoiced + * + * @return $this */ public function setDiscountInvoiced($discountInvoiced) { @@ -3648,7 +3785,9 @@ public function setDiscountInvoiced($discountInvoiced) } /** - * {@inheritdoc} + * Set DiscountRefunded + * + * @return $this */ public function setDiscountRefunded($discountRefunded) { @@ -3656,7 +3795,9 @@ public function setDiscountRefunded($discountRefunded) } /** - * {@inheritdoc} + * Set GrandTotal + * + * @return $this */ public function setGrandTotal($amount) { @@ -3664,7 +3805,9 @@ public function setGrandTotal($amount) } /** - * {@inheritdoc} + * Set ShippingAmount + * + * @return $this */ public function setShippingAmount($amount) { @@ -3672,7 +3815,9 @@ public function setShippingAmount($amount) } /** - * {@inheritdoc} + * Set ShippingCanceled + * + * @return $this */ public function setShippingCanceled($shippingCanceled) { @@ -3680,7 +3825,9 @@ public function setShippingCanceled($shippingCanceled) } /** - * {@inheritdoc} + * Set ShippingInvoiced + * + * @return $this */ public function setShippingInvoiced($shippingInvoiced) { @@ -3688,7 +3835,9 @@ public function setShippingInvoiced($shippingInvoiced) } /** - * {@inheritdoc} + * Set ShippingRefunded + * + * @return $this */ public function setShippingRefunded($shippingRefunded) { @@ -3696,7 +3845,9 @@ public function setShippingRefunded($shippingRefunded) } /** - * {@inheritdoc} + * Set ShippingTaxAmount + * + * @return $this */ public function setShippingTaxAmount($amount) { @@ -3704,7 +3855,9 @@ public function setShippingTaxAmount($amount) } /** - * {@inheritdoc} + * Set ShippingTaxRefunded + * + * @return $this */ public function setShippingTaxRefunded($shippingTaxRefunded) { @@ -3712,7 +3865,9 @@ public function setShippingTaxRefunded($shippingTaxRefunded) } /** - * {@inheritdoc} + * Set StoreToBaseRate + * + * @return $this */ public function setStoreToBaseRate($rate) { @@ -3720,7 +3875,9 @@ public function setStoreToBaseRate($rate) } /** - * {@inheritdoc} + * Set StoreToOrderRate + * + * @return $this */ public function setStoreToOrderRate($rate) { @@ -3728,7 +3885,9 @@ public function setStoreToOrderRate($rate) } /** - * {@inheritdoc} + * Set Subtotal + * + * @return $this */ public function setSubtotal($amount) { @@ -3736,7 +3895,9 @@ public function setSubtotal($amount) } /** - * {@inheritdoc} + * Set SubtotalCanceled + * + * @return $this */ public function setSubtotalCanceled($subtotalCanceled) { @@ -3744,7 +3905,9 @@ public function setSubtotalCanceled($subtotalCanceled) } /** - * {@inheritdoc} + * Set SubtotalInvoiced + * + * @return $this */ public function setSubtotalInvoiced($subtotalInvoiced) { @@ -3752,7 +3915,9 @@ public function setSubtotalInvoiced($subtotalInvoiced) } /** - * {@inheritdoc} + * Set SubtotalRefunded + * + * @return $this */ public function setSubtotalRefunded($subtotalRefunded) { @@ -3760,7 +3925,9 @@ public function setSubtotalRefunded($subtotalRefunded) } /** - * {@inheritdoc} + * Set TaxAmount + * + * @return $this */ public function setTaxAmount($amount) { @@ -3768,7 +3935,9 @@ public function setTaxAmount($amount) } /** - * {@inheritdoc} + * Set TaxCanceled + * + * @return $this */ public function setTaxCanceled($taxCanceled) { @@ -3776,7 +3945,9 @@ public function setTaxCanceled($taxCanceled) } /** - * {@inheritdoc} + * Set TaxInvoiced + * + * @return $this */ public function setTaxInvoiced($taxInvoiced) { @@ -3784,7 +3955,9 @@ public function setTaxInvoiced($taxInvoiced) } /** - * {@inheritdoc} + * Set TaxRefunded + * + * @return $this */ public function setTaxRefunded($taxRefunded) { @@ -3792,7 +3965,9 @@ public function setTaxRefunded($taxRefunded) } /** - * {@inheritdoc} + * Set TotalCanceled + * + * @return $this */ public function setTotalCanceled($totalCanceled) { @@ -3800,7 +3975,9 @@ public function setTotalCanceled($totalCanceled) } /** - * {@inheritdoc} + * Set TotalInvoiced + * + * @return $this */ public function setTotalInvoiced($totalInvoiced) { @@ -3808,7 +3985,9 @@ public function setTotalInvoiced($totalInvoiced) } /** - * {@inheritdoc} + * Set TotalOfflineRefunded + * + * @return $this */ public function setTotalOfflineRefunded($totalOfflineRefunded) { @@ -3816,7 +3995,9 @@ public function setTotalOfflineRefunded($totalOfflineRefunded) } /** - * {@inheritdoc} + * Set TotalOnlineRefunded + * + * @return $this */ public function setTotalOnlineRefunded($totalOnlineRefunded) { @@ -3824,7 +4005,9 @@ public function setTotalOnlineRefunded($totalOnlineRefunded) } /** - * {@inheritdoc} + * Set TotalPaid + * + * @return $this */ public function setTotalPaid($totalPaid) { @@ -3832,7 +4015,9 @@ public function setTotalPaid($totalPaid) } /** - * {@inheritdoc} + * Set TotalQtyOrdered + * + * @return $this */ public function setTotalQtyOrdered($totalQtyOrdered) { @@ -3840,7 +4025,9 @@ public function setTotalQtyOrdered($totalQtyOrdered) } /** - * {@inheritdoc} + * Set TotalRefunded + * + * @return $this */ public function setTotalRefunded($totalRefunded) { @@ -3848,7 +4035,9 @@ public function setTotalRefunded($totalRefunded) } /** - * {@inheritdoc} + * Set CanShipPartially + * + * @return $this */ public function setCanShipPartially($flag) { @@ -3856,7 +4045,9 @@ public function setCanShipPartially($flag) } /** - * {@inheritdoc} + * Set CanShipPartiallyItem + * + * @return $this */ public function setCanShipPartiallyItem($flag) { @@ -3864,7 +4055,9 @@ public function setCanShipPartiallyItem($flag) } /** - * {@inheritdoc} + * Set CustomerIsGuest + * + * @return $this */ public function setCustomerIsGuest($customerIsGuest) { @@ -3872,7 +4065,9 @@ public function setCustomerIsGuest($customerIsGuest) } /** - * {@inheritdoc} + * Set CustomerNoteNotify + * + * @return $this */ public function setCustomerNoteNotify($customerNoteNotify) { @@ -3880,7 +4075,9 @@ public function setCustomerNoteNotify($customerNoteNotify) } /** - * {@inheritdoc} + * Set BillingAddressId + * + * @return $this */ public function setBillingAddressId($id) { @@ -3888,7 +4085,9 @@ public function setBillingAddressId($id) } /** - * {@inheritdoc} + * Set CustomerGroupId + * + * @return $this */ public function setCustomerGroupId($id) { @@ -3896,7 +4095,9 @@ public function setCustomerGroupId($id) } /** - * {@inheritdoc} + * Set EditIncrement + * + * @return $this */ public function setEditIncrement($editIncrement) { @@ -3904,7 +4105,9 @@ public function setEditIncrement($editIncrement) } /** - * {@inheritdoc} + * Set EmailSent + * + * @return $this */ public function setEmailSent($emailSent) { @@ -3912,7 +4115,9 @@ public function setEmailSent($emailSent) } /** - * {@inheritdoc} + * Set ForcedShipmentWithInvoice + * + * @return $this */ public function setForcedShipmentWithInvoice($forcedShipmentWithInvoice) { @@ -3920,7 +4125,9 @@ public function setForcedShipmentWithInvoice($forcedShipmentWithInvoice) } /** - * {@inheritdoc} + * Set PaymentAuthExpiration + * + * @return $this */ public function setPaymentAuthExpiration($paymentAuthExpiration) { @@ -3928,7 +4135,9 @@ public function setPaymentAuthExpiration($paymentAuthExpiration) } /** - * {@inheritdoc} + * Set QuoteAddressId + * + * @return $this */ public function setQuoteAddressId($id) { @@ -3936,7 +4145,9 @@ public function setQuoteAddressId($id) } /** - * {@inheritdoc} + * Set QuoteId + * + * @return $this */ public function setQuoteId($id) { @@ -3944,7 +4155,9 @@ public function setQuoteId($id) } /** - * {@inheritdoc} + * Set AdjustmentNegative + * + * @return $this */ public function setAdjustmentNegative($adjustmentNegative) { @@ -3952,7 +4165,9 @@ public function setAdjustmentNegative($adjustmentNegative) } /** - * {@inheritdoc} + * Set AdjustmentPositive + * + * @return $this */ public function setAdjustmentPositive($adjustmentPositive) { @@ -3960,7 +4175,9 @@ public function setAdjustmentPositive($adjustmentPositive) } /** - * {@inheritdoc} + * Set BaseAdjustmentNegative + * + * @return $this */ public function setBaseAdjustmentNegative($baseAdjustmentNegative) { @@ -3968,7 +4185,9 @@ public function setBaseAdjustmentNegative($baseAdjustmentNegative) } /** - * {@inheritdoc} + * Set BaseAdjustmentPositive + * + * @return $this */ public function setBaseAdjustmentPositive($baseAdjustmentPositive) { @@ -3976,7 +4195,9 @@ public function setBaseAdjustmentPositive($baseAdjustmentPositive) } /** - * {@inheritdoc} + * Set BaseShippingDiscountAmount + * + * @return $this */ public function setBaseShippingDiscountAmount($amount) { @@ -3984,7 +4205,9 @@ public function setBaseShippingDiscountAmount($amount) } /** - * {@inheritdoc} + * Set BaseSubtotalInclTax + * + * @return $this */ public function setBaseSubtotalInclTax($amount) { @@ -3992,7 +4215,9 @@ public function setBaseSubtotalInclTax($amount) } /** - * {@inheritdoc} + * Set BaseTotalDue + * + * @return $this */ public function setBaseTotalDue($baseTotalDue) { @@ -4000,7 +4225,9 @@ public function setBaseTotalDue($baseTotalDue) } /** - * {@inheritdoc} + * Set PaymentAuthorizationAmount + * + * @return $this */ public function setPaymentAuthorizationAmount($amount) { @@ -4008,7 +4235,9 @@ public function setPaymentAuthorizationAmount($amount) } /** - * {@inheritdoc} + * Set ShippingDiscountAmount + * + * @return $this */ public function setShippingDiscountAmount($amount) { @@ -4016,7 +4245,9 @@ public function setShippingDiscountAmount($amount) } /** - * {@inheritdoc} + * Set SubtotalInclTax + * + * @return $this */ public function setSubtotalInclTax($amount) { @@ -4024,7 +4255,9 @@ public function setSubtotalInclTax($amount) } /** - * {@inheritdoc} + * Set TotalDue + * + * @return $this */ public function setTotalDue($totalDue) { @@ -4032,7 +4265,9 @@ public function setTotalDue($totalDue) } /** - * {@inheritdoc} + * Set Weight + * + * @return $this */ public function setWeight($weight) { @@ -4040,7 +4275,9 @@ public function setWeight($weight) } /** - * {@inheritdoc} + * Set CustomerDob + * + * @return $this */ public function setCustomerDob($customerDob) { @@ -4048,7 +4285,9 @@ public function setCustomerDob($customerDob) } /** - * {@inheritdoc} + * Set IncrementId + * + * @return $this */ public function setIncrementId($id) { @@ -4056,7 +4295,9 @@ public function setIncrementId($id) } /** - * {@inheritdoc} + * Set AppliedRuleIds + * + * @return $this */ public function setAppliedRuleIds($appliedRuleIds) { @@ -4064,7 +4305,9 @@ public function setAppliedRuleIds($appliedRuleIds) } /** - * {@inheritdoc} + * Set BaseCurrencyCode + * + * @return $this */ public function setBaseCurrencyCode($code) { @@ -4072,7 +4315,9 @@ public function setBaseCurrencyCode($code) } /** - * {@inheritdoc} + * Set CustomerEmail + * + * @return $this */ public function setCustomerEmail($customerEmail) { @@ -4080,7 +4325,9 @@ public function setCustomerEmail($customerEmail) } /** - * {@inheritdoc} + * Set CustomerFirstname + * + * @return $this */ public function setCustomerFirstname($customerFirstname) { @@ -4088,7 +4335,9 @@ public function setCustomerFirstname($customerFirstname) } /** - * {@inheritdoc} + * Set CustomerLastname + * + * @return $this */ public function setCustomerLastname($customerLastname) { @@ -4096,7 +4345,9 @@ public function setCustomerLastname($customerLastname) } /** - * {@inheritdoc} + * Set CustomerMiddlename + * + * @return $this */ public function setCustomerMiddlename($customerMiddlename) { @@ -4104,7 +4355,9 @@ public function setCustomerMiddlename($customerMiddlename) } /** - * {@inheritdoc} + * Set CustomerPrefix + * + * @return $this */ public function setCustomerPrefix($customerPrefix) { @@ -4112,7 +4365,9 @@ public function setCustomerPrefix($customerPrefix) } /** - * {@inheritdoc} + * Set CustomerSuffix + * + * @return $this */ public function setCustomerSuffix($customerSuffix) { @@ -4120,7 +4375,9 @@ public function setCustomerSuffix($customerSuffix) } /** - * {@inheritdoc} + * Set CustomerTaxvat + * + * @return $this */ public function setCustomerTaxvat($customerTaxvat) { @@ -4128,7 +4385,9 @@ public function setCustomerTaxvat($customerTaxvat) } /** - * {@inheritdoc} + * Set DiscountDescription + * + * @return $this */ public function setDiscountDescription($description) { @@ -4136,7 +4395,9 @@ public function setDiscountDescription($description) } /** - * {@inheritdoc} + * Set ExtCustomerId + * + * @return $this */ public function setExtCustomerId($id) { @@ -4144,7 +4405,9 @@ public function setExtCustomerId($id) } /** - * {@inheritdoc} + * Set ExtOrderId + * + * @return $this */ public function setExtOrderId($id) { @@ -4152,7 +4415,9 @@ public function setExtOrderId($id) } /** - * {@inheritdoc} + * Set GlobalCurrencyCode + * + * @return $this */ public function setGlobalCurrencyCode($code) { @@ -4160,7 +4425,9 @@ public function setGlobalCurrencyCode($code) } /** - * {@inheritdoc} + * Set HoldBeforeState + * + * @return $this */ public function setHoldBeforeState($holdBeforeState) { @@ -4168,7 +4435,9 @@ public function setHoldBeforeState($holdBeforeState) } /** - * {@inheritdoc} + * Set HoldBeforeStatus + * + * @return $this */ public function setHoldBeforeStatus($holdBeforeStatus) { @@ -4176,7 +4445,9 @@ public function setHoldBeforeStatus($holdBeforeStatus) } /** - * {@inheritdoc} + * Set OrderCurrencyCode + * + * @return $this */ public function setOrderCurrencyCode($code) { @@ -4184,7 +4455,9 @@ public function setOrderCurrencyCode($code) } /** - * {@inheritdoc} + * Set OriginalIncrementId + * + * @return $this */ public function setOriginalIncrementId($id) { @@ -4192,7 +4465,9 @@ public function setOriginalIncrementId($id) } /** - * {@inheritdoc} + * Set RelationChildId + * + * @return $this */ public function setRelationChildId($id) { @@ -4200,7 +4475,9 @@ public function setRelationChildId($id) } /** - * {@inheritdoc} + * Set RelationChildRealId + * + * @return $this */ public function setRelationChildRealId($realId) { @@ -4208,7 +4485,9 @@ public function setRelationChildRealId($realId) } /** - * {@inheritdoc} + * Set RelationParentId + * + * @return $this */ public function setRelationParentId($id) { @@ -4216,7 +4495,9 @@ public function setRelationParentId($id) } /** - * {@inheritdoc} + * Set RelationParentRealId + * + * @return $this */ public function setRelationParentRealId($realId) { @@ -4224,7 +4505,9 @@ public function setRelationParentRealId($realId) } /** - * {@inheritdoc} + * Set RemoteIp + * + * @return $this */ public function setRemoteIp($remoteIp) { @@ -4232,7 +4515,9 @@ public function setRemoteIp($remoteIp) } /** - * {@inheritdoc} + * Set StoreCurrencyCode + * + * @return $this */ public function setStoreCurrencyCode($code) { @@ -4240,7 +4525,9 @@ public function setStoreCurrencyCode($code) } /** - * {@inheritdoc} + * Set StoreName + * + * @return $this */ public function setStoreName($storeName) { @@ -4248,7 +4535,9 @@ public function setStoreName($storeName) } /** - * {@inheritdoc} + * Set XForwardedFor + * + * @return $this */ public function setXForwardedFor($xForwardedFor) { @@ -4256,7 +4545,9 @@ public function setXForwardedFor($xForwardedFor) } /** - * {@inheritdoc} + * Set CustomerNote + * + * @return $this */ public function setCustomerNote($customerNote) { @@ -4264,7 +4555,9 @@ public function setCustomerNote($customerNote) } /** - * {@inheritdoc} + * Set UpdatedAt + * + * @return $this */ public function setUpdatedAt($timestamp) { @@ -4272,7 +4565,9 @@ public function setUpdatedAt($timestamp) } /** - * {@inheritdoc} + * Set TotalItemCount + * + * @return $this */ public function setTotalItemCount($totalItemCount) { @@ -4280,7 +4575,9 @@ public function setTotalItemCount($totalItemCount) } /** - * {@inheritdoc} + * Set CustomerGender + * + * @return $this */ public function setCustomerGender($customerGender) { @@ -4288,7 +4585,9 @@ public function setCustomerGender($customerGender) } /** - * {@inheritdoc} + * Set DiscountTaxCompensationAmount + * + * @return $this */ public function setDiscountTaxCompensationAmount($amount) { @@ -4296,7 +4595,9 @@ public function setDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * Set BaseDiscountTaxCompensationAmount + * + * @return $this */ public function setBaseDiscountTaxCompensationAmount($amount) { @@ -4304,7 +4605,9 @@ public function setBaseDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * Set ShippingDiscountTaxCompensationAmount + * + * @return $this */ public function setShippingDiscountTaxCompensationAmount($amount) { @@ -4312,7 +4615,9 @@ public function setShippingDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * Set BaseShippingDiscountTaxCompensationAmnt + * + * @return $this */ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) { @@ -4320,7 +4625,9 @@ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) } /** - * {@inheritdoc} + * Set DiscountTaxCompensationInvoiced + * + * @return $this */ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoiced) { @@ -4328,7 +4635,9 @@ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoi } /** - * {@inheritdoc} + * Set BaseDiscountTaxCompensationInvoiced + * + * @return $this */ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensationInvoiced) { @@ -4339,7 +4648,9 @@ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensat } /** - * {@inheritdoc} + * Set DiscountTaxCompensationRefunded + * + * @return $this */ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefunded) { @@ -4350,7 +4661,9 @@ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefun } /** - * {@inheritdoc} + * Set BaseDiscountTaxCompensationRefunded + * + * @return $this */ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensationRefunded) { @@ -4361,7 +4674,9 @@ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensat } /** - * {@inheritdoc} + * Set ShippingInclTax + * + * @return $this */ public function setShippingInclTax($amount) { @@ -4369,7 +4684,7 @@ public function setShippingInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingInclTax($amount) { From d0b30a999698de2db9e05a89c1abbf4695c5bee1 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 17 Sep 2018 12:05:30 -0500 Subject: [PATCH 036/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fix static tests --- app/code/Magento/Sales/Model/Order/Item.php | 210 +++++++++--------- .../Sales/Test/Unit/Model/OrderTest.php | 1 + 2 files changed, 106 insertions(+), 105 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php index 7fa2f61554563..423d4b8d09d44 100644 --- a/app/code/Magento/Sales/Model/Order/Item.php +++ b/app/code/Magento/Sales/Model/Order/Item.php @@ -483,6 +483,7 @@ public function getProductOptions() /** * Get product options array by code. + * * If code is null return all options * * @param string $code @@ -540,8 +541,7 @@ public function getChildrenItems() } /** - * Return checking of what calculation - * type was for this product + * Return checking of what calculation type was for this product * * @return bool */ @@ -581,8 +581,7 @@ public function getForceApplyDiscountToParentItem() } /** - * Return checking of what shipment - * type was for this product + * Return checking of what shipment type was for this product * * @return bool */ @@ -605,9 +604,9 @@ public function isShipSeparately() } /** - * This is Dummy item or not - * if $shipment is true then we checking this for shipping situation if not - * then we checking this for calculation + * This is Dummy item or not. + * + * If $shipment is true then we checking this for shipping situation if not, we checking this for calculation. * * @param bool $shipment * @return bool @@ -652,8 +651,9 @@ public function isDummy($shipment = false) } /** - * Returns formatted buy request - object, holding request received from - * product view page with keys and options for configured product + * Returns formatted buy request. + * + * This object is holding request received from product view page with keys and options for configured product. * * @return \Magento\Framework\DataObject */ @@ -963,7 +963,7 @@ public function getCreatedAt() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCreatedAt($createdAt) { @@ -1621,7 +1621,7 @@ public function getWeight() } /** - * {@inheritdoc} + * @inheritdoc */ public function setUpdatedAt($timestamp) { @@ -1629,7 +1629,7 @@ public function setUpdatedAt($timestamp) } /** - * {@inheritdoc} + * @inheritdoc */ public function setItemId($id) { @@ -1637,7 +1637,7 @@ public function setItemId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setOrderId($id) { @@ -1645,7 +1645,7 @@ public function setOrderId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setParentItemId($id) { @@ -1653,7 +1653,7 @@ public function setParentItemId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQuoteItemId($id) { @@ -1661,7 +1661,7 @@ public function setQuoteItemId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreId($id) { @@ -1669,7 +1669,7 @@ public function setStoreId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setProductId($id) { @@ -1677,7 +1677,7 @@ public function setProductId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setProductType($productType) { @@ -1685,7 +1685,7 @@ public function setProductType($productType) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeight($weight) { @@ -1693,7 +1693,7 @@ public function setWeight($weight) } /** - * {@inheritdoc} + * @inheritdoc */ public function setIsVirtual($isVirtual) { @@ -1701,7 +1701,7 @@ public function setIsVirtual($isVirtual) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSku($sku) { @@ -1709,7 +1709,7 @@ public function setSku($sku) } /** - * {@inheritdoc} + * @inheritdoc */ public function setName($name) { @@ -1717,7 +1717,7 @@ public function setName($name) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDescription($description) { @@ -1725,7 +1725,7 @@ public function setDescription($description) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAppliedRuleIds($appliedRuleIds) { @@ -1733,7 +1733,7 @@ public function setAppliedRuleIds($appliedRuleIds) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAdditionalData($additionalData) { @@ -1741,7 +1741,7 @@ public function setAdditionalData($additionalData) } /** - * {@inheritdoc} + * @inheritdoc */ public function setIsQtyDecimal($isQtyDecimal) { @@ -1749,7 +1749,7 @@ public function setIsQtyDecimal($isQtyDecimal) } /** - * {@inheritdoc} + * @inheritdoc */ public function setNoDiscount($noDiscount) { @@ -1757,7 +1757,7 @@ public function setNoDiscount($noDiscount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyBackordered($qtyBackordered) { @@ -1765,7 +1765,7 @@ public function setQtyBackordered($qtyBackordered) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyCanceled($qtyCanceled) { @@ -1773,7 +1773,7 @@ public function setQtyCanceled($qtyCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyInvoiced($qtyInvoiced) { @@ -1781,7 +1781,7 @@ public function setQtyInvoiced($qtyInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyOrdered($qtyOrdered) { @@ -1789,7 +1789,7 @@ public function setQtyOrdered($qtyOrdered) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyRefunded($qtyRefunded) { @@ -1797,7 +1797,7 @@ public function setQtyRefunded($qtyRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyShipped($qtyShipped) { @@ -1805,7 +1805,7 @@ public function setQtyShipped($qtyShipped) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseCost($baseCost) { @@ -1813,7 +1813,7 @@ public function setBaseCost($baseCost) } /** - * {@inheritdoc} + * @inheritdoc */ public function setPrice($price) { @@ -1821,7 +1821,7 @@ public function setPrice($price) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBasePrice($price) { @@ -1829,7 +1829,7 @@ public function setBasePrice($price) } /** - * {@inheritdoc} + * @inheritdoc */ public function setOriginalPrice($price) { @@ -1837,7 +1837,7 @@ public function setOriginalPrice($price) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseOriginalPrice($price) { @@ -1845,7 +1845,7 @@ public function setBaseOriginalPrice($price) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxPercent($taxPercent) { @@ -1853,7 +1853,7 @@ public function setTaxPercent($taxPercent) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxAmount($amount) { @@ -1861,7 +1861,7 @@ public function setTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxAmount($amount) { @@ -1869,7 +1869,7 @@ public function setBaseTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxInvoiced($taxInvoiced) { @@ -1877,7 +1877,7 @@ public function setTaxInvoiced($taxInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxInvoiced($baseTaxInvoiced) { @@ -1885,7 +1885,7 @@ public function setBaseTaxInvoiced($baseTaxInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountPercent($discountPercent) { @@ -1893,7 +1893,7 @@ public function setDiscountPercent($discountPercent) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountAmount($amount) { @@ -1901,7 +1901,7 @@ public function setDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountAmount($amount) { @@ -1909,7 +1909,7 @@ public function setBaseDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountInvoiced($discountInvoiced) { @@ -1917,7 +1917,7 @@ public function setDiscountInvoiced($discountInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountInvoiced($baseDiscountInvoiced) { @@ -1925,7 +1925,7 @@ public function setBaseDiscountInvoiced($baseDiscountInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAmountRefunded($amountRefunded) { @@ -1933,7 +1933,7 @@ public function setAmountRefunded($amountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseAmountRefunded($baseAmountRefunded) { @@ -1941,7 +1941,7 @@ public function setBaseAmountRefunded($baseAmountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRowTotal($amount) { @@ -1949,7 +1949,7 @@ public function setRowTotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseRowTotal($amount) { @@ -1957,7 +1957,7 @@ public function setBaseRowTotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRowInvoiced($rowInvoiced) { @@ -1965,7 +1965,7 @@ public function setRowInvoiced($rowInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseRowInvoiced($baseRowInvoiced) { @@ -1973,7 +1973,7 @@ public function setBaseRowInvoiced($baseRowInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRowWeight($rowWeight) { @@ -1981,7 +1981,7 @@ public function setRowWeight($rowWeight) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxBeforeDiscount($baseTaxBeforeDiscount) { @@ -1989,7 +1989,7 @@ public function setBaseTaxBeforeDiscount($baseTaxBeforeDiscount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxBeforeDiscount($taxBeforeDiscount) { @@ -1997,7 +1997,7 @@ public function setTaxBeforeDiscount($taxBeforeDiscount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setExtOrderItemId($id) { @@ -2005,7 +2005,7 @@ public function setExtOrderItemId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setLockedDoInvoice($flag) { @@ -2013,7 +2013,7 @@ public function setLockedDoInvoice($flag) } /** - * {@inheritdoc} + * @inheritdoc */ public function setLockedDoShip($flag) { @@ -2021,7 +2021,7 @@ public function setLockedDoShip($flag) } /** - * {@inheritdoc} + * @inheritdoc */ public function setPriceInclTax($amount) { @@ -2029,7 +2029,7 @@ public function setPriceInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBasePriceInclTax($amount) { @@ -2037,7 +2037,7 @@ public function setBasePriceInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRowTotalInclTax($amount) { @@ -2045,7 +2045,7 @@ public function setRowTotalInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseRowTotalInclTax($amount) { @@ -2053,7 +2053,7 @@ public function setBaseRowTotalInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationAmount($amount) { @@ -2061,7 +2061,7 @@ public function setDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationAmount($amount) { @@ -2069,7 +2069,7 @@ public function setBaseDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoiced) { @@ -2077,7 +2077,7 @@ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoi } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensationInvoiced) { @@ -2088,7 +2088,7 @@ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensat } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefunded) { @@ -2096,7 +2096,7 @@ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefun } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensationRefunded) { @@ -2107,7 +2107,7 @@ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensat } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxCanceled($taxCanceled) { @@ -2115,7 +2115,7 @@ public function setTaxCanceled($taxCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationCanceled($discountTaxCompensationCanceled) { @@ -2123,7 +2123,7 @@ public function setDiscountTaxCompensationCanceled($discountTaxCompensationCance } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxRefunded($taxRefunded) { @@ -2131,7 +2131,7 @@ public function setTaxRefunded($taxRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxRefunded($baseTaxRefunded) { @@ -2139,7 +2139,7 @@ public function setBaseTaxRefunded($baseTaxRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountRefunded($discountRefunded) { @@ -2147,7 +2147,7 @@ public function setDiscountRefunded($discountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountRefunded($baseDiscountRefunded) { @@ -2155,7 +2155,7 @@ public function setBaseDiscountRefunded($baseDiscountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwId($id) { @@ -2163,7 +2163,7 @@ public function setGwId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwBasePrice($price) { @@ -2171,7 +2171,7 @@ public function setGwBasePrice($price) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwPrice($price) { @@ -2179,7 +2179,7 @@ public function setGwPrice($price) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwBaseTaxAmount($amount) { @@ -2187,7 +2187,7 @@ public function setGwBaseTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwTaxAmount($amount) { @@ -2195,7 +2195,7 @@ public function setGwTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwBasePriceInvoiced($gwBasePriceInvoiced) { @@ -2203,7 +2203,7 @@ public function setGwBasePriceInvoiced($gwBasePriceInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwPriceInvoiced($gwPriceInvoiced) { @@ -2211,7 +2211,7 @@ public function setGwPriceInvoiced($gwPriceInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwBaseTaxAmountInvoiced($gwBaseTaxAmountInvoiced) { @@ -2219,7 +2219,7 @@ public function setGwBaseTaxAmountInvoiced($gwBaseTaxAmountInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwTaxAmountInvoiced($gwTaxAmountInvoiced) { @@ -2227,7 +2227,7 @@ public function setGwTaxAmountInvoiced($gwTaxAmountInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwBasePriceRefunded($gwBasePriceRefunded) { @@ -2235,7 +2235,7 @@ public function setGwBasePriceRefunded($gwBasePriceRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwPriceRefunded($gwPriceRefunded) { @@ -2243,7 +2243,7 @@ public function setGwPriceRefunded($gwPriceRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwBaseTaxAmountRefunded($gwBaseTaxAmountRefunded) { @@ -2251,7 +2251,7 @@ public function setGwBaseTaxAmountRefunded($gwBaseTaxAmountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGwTaxAmountRefunded($gwTaxAmountRefunded) { @@ -2259,7 +2259,7 @@ public function setGwTaxAmountRefunded($gwTaxAmountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setFreeShipping($freeShipping) { @@ -2267,7 +2267,7 @@ public function setFreeShipping($freeShipping) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQtyReturned($qtyReturned) { @@ -2275,7 +2275,7 @@ public function setQtyReturned($qtyReturned) } /** - * {@inheritdoc} + * @inheritdoc */ public function setEventId($id) { @@ -2283,7 +2283,7 @@ public function setEventId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseWeeeTaxAppliedAmount($amount) { @@ -2291,7 +2291,7 @@ public function setBaseWeeeTaxAppliedAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseWeeeTaxAppliedRowAmnt($amnt) { @@ -2299,7 +2299,7 @@ public function setBaseWeeeTaxAppliedRowAmnt($amnt) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeeeTaxAppliedAmount($amount) { @@ -2307,7 +2307,7 @@ public function setWeeeTaxAppliedAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeeeTaxAppliedRowAmount($amount) { @@ -2315,7 +2315,7 @@ public function setWeeeTaxAppliedRowAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeeeTaxApplied($weeeTaxApplied) { @@ -2323,7 +2323,7 @@ public function setWeeeTaxApplied($weeeTaxApplied) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeeeTaxDisposition($weeeTaxDisposition) { @@ -2331,7 +2331,7 @@ public function setWeeeTaxDisposition($weeeTaxDisposition) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeeeTaxRowDisposition($weeeTaxRowDisposition) { @@ -2339,7 +2339,7 @@ public function setWeeeTaxRowDisposition($weeeTaxRowDisposition) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseWeeeTaxDisposition($baseWeeeTaxDisposition) { @@ -2347,7 +2347,7 @@ public function setBaseWeeeTaxDisposition($baseWeeeTaxDisposition) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseWeeeTaxRowDisposition($baseWeeeTaxRowDisposition) { @@ -2355,7 +2355,7 @@ public function setBaseWeeeTaxRowDisposition($baseWeeeTaxRowDisposition) } /** - * {@inheritdoc} + * @inheritdoc */ public function getProductOption() { @@ -2363,7 +2363,7 @@ public function getProductOption() } /** - * {@inheritdoc} + * @inheritdoc */ public function setProductOption(\Magento\Catalog\Api\Data\ProductOptionInterface $productOption) { @@ -2371,7 +2371,7 @@ public function setProductOption(\Magento\Catalog\Api\Data\ProductOptionInterfac } /** - * {@inheritdoc} + * @inheritdoc * * @return \Magento\Sales\Api\Data\OrderItemExtensionInterface|null */ @@ -2381,7 +2381,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * @inheritdoc * * @param \Magento\Sales\Api\Data\OrderItemExtensionInterface $extensionAttributes * @return $this diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index b75e3adb7402b..873cd64e9c364 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -18,6 +18,7 @@ * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.TooManyPublicMethods) + * @SuppressWarnings(PHPMD.ExcessivePublicCount) */ class OrderTest extends \PHPUnit\Framework\TestCase { From cb428a129e74c5e520478995d4e4b1856d1c39ca Mon Sep 17 00:00:00 2001 From: Devagouda Patil <depatil@Devagoudas-MacBook-Pro.local> Date: Mon, 17 Sep 2018 12:51:21 -0500 Subject: [PATCH 037/118] MAGETWO-93993: MFTF Flaky Test: StorefrontCustomerCheckoutTestWithMultipleAddressesAndTaxRates - Added fix for the MFTF test --- .../Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml index 6ea8d8a167294..13e4e286311b2 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml @@ -91,9 +91,7 @@ <description value="Should be able to place an order as a customer with multiple addresses and tax rates."/> <testCaseId value="MAGETWO-93109"/> <severity value="AVERAGE"/> - <skip> - <issueId value="MQE-1187" /> - </skip> + <group value="checkout"/> </annotations> <before> <createData entity="SimpleSubCategory" stepKey="simplecategory"/> @@ -183,6 +181,8 @@ <click stepKey="changeShippingAddress" selector="{{CheckoutShippingMethodsSection.shipHereButton}}"/> <waitForElementNotVisible stepKey="waitForShippingMethodLoaderNotVisible" selector="{{CheckoutShippingMethodsSection.shippingMethodLoader}}" time="30"/> + <waitForElementVisible stepKey="waitForShippingMethodRadioToBeVisible" selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" time="30"/> + <waitForPageLoad stepKey="waitForPageLoad23"/> <click stepKey="selectFirstShippingMethod2" selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}"/> <waitForElement stepKey="waitForShippingMethodSelect2" selector="{{CheckoutShippingMethodsSection.next}}" time="30"/> <click stepKey="clickNextOnShippingMethodLoad2" selector="{{CheckoutShippingMethodsSection.next}}" /> From e1b02178c68dceadb10ca1667ab9ffadd21c3948 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 17 Sep 2018 13:35:37 -0500 Subject: [PATCH 038/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fix static tests --- app/code/Magento/Sales/Model/Order.php | 542 +++++--------------- app/code/Magento/Sales/Model/Order/Item.php | 184 +++---- 2 files changed, 233 insertions(+), 493 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 47979591a5843..14c6154f0cb0a 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -979,7 +979,7 @@ public function getShippingAddress() } /** - * Set order state + * @inheritdoc * * @param string $state * @return $this @@ -1496,9 +1496,7 @@ public function getPaymentById($paymentId) } /** - * Set payment - * - * @return \Magento\Sales\Api\Data\OrderPaymentInterface|null + * @inheritdoc */ public function setPayment(\Magento\Sales\Api\Data\OrderPaymentInterface $payment = null) { @@ -1581,7 +1579,7 @@ public function getStatusHistoryById($statusId) } /** - * Set the order status history object and the order object to each other. + * @inheritdoc * * Adds the object to the status history collection, which is automatically saved when the order is saved. * See the entity_id attribute backend model. @@ -1632,9 +1630,9 @@ public function getOrderCurrency() /** * Get formatted price value including order currency rate to order website currency * - * @param float $price - * @param bool $addBrackets - * @return string + * @param float $price + * @param bool $addBrackets + * @return string */ public function formatPrice($price, $addBrackets = false) { @@ -1773,7 +1771,7 @@ public function getInvoiceCollection() } /** - * Set order invoices collection + * @inheritdoc * * @param InvoiceCollection $invoices * @return $this @@ -1878,6 +1876,8 @@ public function getRelatedObjects() } /** + * Get customer name + * * @return string */ public function getCustomerName() @@ -2031,9 +2031,7 @@ public function getItems() } /** - * Set Items - * - * @return $this + * @inheritdoc * @codeCoverageIgnore */ public function setItems($items) @@ -2084,7 +2082,7 @@ public function getExtensionAttributes() } /** - * Set ExtensionAttributes + * @inheritdoc * * @param \Magento\Sales\Api\Data\OrderExtensionInterface $extensionAttributes * @return $this @@ -2288,7 +2286,7 @@ public function getBaseShippingInclTax() /** * Return base_shipping_invoiced - + * * @return float|null */ public function getBaseShippingInvoiced() @@ -3385,9 +3383,7 @@ public function getXForwardedFor() } /** - * Set StatusHistories - * - * @return $this + * @inheritdoc */ public function setStatusHistories(array $statusHistories = null) { @@ -3395,9 +3391,7 @@ public function setStatusHistories(array $statusHistories = null) } /** - * Set Status - * - * @return $this + * @inheritdoc */ public function setStatus($status) { @@ -3405,9 +3399,7 @@ public function setStatus($status) } /** - * Set CouponCode - * - * @return $this + * @inheritdoc */ public function setCouponCode($code) { @@ -3415,9 +3407,7 @@ public function setCouponCode($code) } /** - * Set ProtectCode - * - * @return $this + * @inheritdoc */ public function setProtectCode($code) { @@ -3425,9 +3415,7 @@ public function setProtectCode($code) } /** - * Set ShippingDescription - * - * @return $this + * @inheritdoc */ public function setShippingDescription($description) { @@ -3435,9 +3423,7 @@ public function setShippingDescription($description) } /** - * Set IsVirtual - * - * @return $this + * @inheritdoc */ public function setIsVirtual($isVirtual) { @@ -3445,9 +3431,7 @@ public function setIsVirtual($isVirtual) } /** - * Set StoreId - * - * @return $this + * @inheritdoc */ public function setStoreId($id) { @@ -3455,9 +3439,7 @@ public function setStoreId($id) } /** - * Set CustomerId - * - * @return $this + * @inheritdoc */ public function setCustomerId($id) { @@ -3465,9 +3447,7 @@ public function setCustomerId($id) } /** - * Set BaseDiscountAmount - * - * @return $this + * @inheritdoc */ public function setBaseDiscountAmount($amount) { @@ -3475,9 +3455,7 @@ public function setBaseDiscountAmount($amount) } /** - * Set BaseDiscountCanceled - * - * @return $this + * @inheritdoc */ public function setBaseDiscountCanceled($baseDiscountCanceled) { @@ -3485,9 +3463,7 @@ public function setBaseDiscountCanceled($baseDiscountCanceled) } /** - * Set BaseDiscountInvoiced - * - * @return $this + * @inheritdoc */ public function setBaseDiscountInvoiced($baseDiscountInvoiced) { @@ -3495,9 +3471,7 @@ public function setBaseDiscountInvoiced($baseDiscountInvoiced) } /** - * Set BaseDiscountRefunded - * - * @return $this + * @inheritdoc */ public function setBaseDiscountRefunded($baseDiscountRefunded) { @@ -3505,9 +3479,7 @@ public function setBaseDiscountRefunded($baseDiscountRefunded) } /** - * Set BaseGrandTotal - * - * @return $this + * @inheritdoc */ public function setBaseGrandTotal($amount) { @@ -3515,9 +3487,7 @@ public function setBaseGrandTotal($amount) } /** - * Set BaseShippingAmount - * - * @return $this + * @inheritdoc */ public function setBaseShippingAmount($amount) { @@ -3525,9 +3495,7 @@ public function setBaseShippingAmount($amount) } /** - * Set BaseShippingCanceled - * - * @return $this + * @inheritdoc */ public function setBaseShippingCanceled($baseShippingCanceled) { @@ -3535,9 +3503,7 @@ public function setBaseShippingCanceled($baseShippingCanceled) } /** - * Set BaseShippingInvoiced - * - * @return $this + * @inheritdoc */ public function setBaseShippingInvoiced($baseShippingInvoiced) { @@ -3545,9 +3511,7 @@ public function setBaseShippingInvoiced($baseShippingInvoiced) } /** - * Set BaseShippingRefunded - * - * @return $this + * @inheritdoc */ public function setBaseShippingRefunded($baseShippingRefunded) { @@ -3555,9 +3519,7 @@ public function setBaseShippingRefunded($baseShippingRefunded) } /** - * Set BaseShippingTaxAmount - * - * @return $this + * @inheritdoc */ public function setBaseShippingTaxAmount($amount) { @@ -3565,9 +3527,7 @@ public function setBaseShippingTaxAmount($amount) } /** - * Set BaseShippingTaxRefunded - * - * @return $this + * @inheritdoc */ public function setBaseShippingTaxRefunded($baseShippingTaxRefunded) { @@ -3575,9 +3535,7 @@ public function setBaseShippingTaxRefunded($baseShippingTaxRefunded) } /** - * Set BaseSubtotal - * - * @return $this + * @inheritdoc */ public function setBaseSubtotal($amount) { @@ -3585,9 +3543,7 @@ public function setBaseSubtotal($amount) } /** - * Set BaseSubtotalCanceled - * - * @return $this + * @inheritdoc */ public function setBaseSubtotalCanceled($baseSubtotalCanceled) { @@ -3595,9 +3551,7 @@ public function setBaseSubtotalCanceled($baseSubtotalCanceled) } /** - * Set BaseSubtotalInvoiced - * - * @return $this + * @inheritdoc */ public function setBaseSubtotalInvoiced($baseSubtotalInvoiced) { @@ -3605,9 +3559,7 @@ public function setBaseSubtotalInvoiced($baseSubtotalInvoiced) } /** - * Set BaseSubtotalRefunded - * - * @return $this + * @inheritdoc */ public function setBaseSubtotalRefunded($baseSubtotalRefunded) { @@ -3615,9 +3567,7 @@ public function setBaseSubtotalRefunded($baseSubtotalRefunded) } /** - * Set BaseTaxAmount - * - * @return $this + * @inheritdoc */ public function setBaseTaxAmount($amount) { @@ -3625,9 +3575,7 @@ public function setBaseTaxAmount($amount) } /** - * Set BaseTaxCanceled - * - * @return $this + * @inheritdoc */ public function setBaseTaxCanceled($baseTaxCanceled) { @@ -3635,9 +3583,7 @@ public function setBaseTaxCanceled($baseTaxCanceled) } /** - * Set BaseTaxInvoiced - * - * @return $this + * @inheritdoc */ public function setBaseTaxInvoiced($baseTaxInvoiced) { @@ -3645,9 +3591,7 @@ public function setBaseTaxInvoiced($baseTaxInvoiced) } /** - * Set BaseTaxRefunded - * - * @return $this + * @inheritdoc */ public function setBaseTaxRefunded($baseTaxRefunded) { @@ -3655,9 +3599,7 @@ public function setBaseTaxRefunded($baseTaxRefunded) } /** - * Set BaseToGlobalRate - * - * @return $this + * @inheritdoc */ public function setBaseToGlobalRate($rate) { @@ -3665,9 +3607,7 @@ public function setBaseToGlobalRate($rate) } /** - * Set BaseToOrderRate - * - * @return $this + * @inheritdoc */ public function setBaseToOrderRate($rate) { @@ -3675,9 +3615,7 @@ public function setBaseToOrderRate($rate) } /** - * Set BaseTotalCanceled - * - * @return $this + * @inheritdoc */ public function setBaseTotalCanceled($baseTotalCanceled) { @@ -3685,9 +3623,7 @@ public function setBaseTotalCanceled($baseTotalCanceled) } /** - * Set BaseTotalInvoiced - * - * @return $this + * @inheritdoc */ public function setBaseTotalInvoiced($baseTotalInvoiced) { @@ -3695,9 +3631,7 @@ public function setBaseTotalInvoiced($baseTotalInvoiced) } /** - * Set BaseTotalInvoicedCost - * - * @return $this + * @inheritdoc */ public function setBaseTotalInvoicedCost($baseTotalInvoicedCost) { @@ -3705,9 +3639,7 @@ public function setBaseTotalInvoicedCost($baseTotalInvoicedCost) } /** - * Set BaseTotalOfflineRefunded - * - * @return $this + * @inheritdoc */ public function setBaseTotalOfflineRefunded($baseTotalOfflineRefunded) { @@ -3715,9 +3647,7 @@ public function setBaseTotalOfflineRefunded($baseTotalOfflineRefunded) } /** - * Set BaseTotalOnlineRefunded - * - * @return $this + * @inheritdoc */ public function setBaseTotalOnlineRefunded($baseTotalOnlineRefunded) { @@ -3725,9 +3655,7 @@ public function setBaseTotalOnlineRefunded($baseTotalOnlineRefunded) } /** - * Set BaseTotalPaid - * - * @return $this + * @inheritdoc */ public function setBaseTotalPaid($baseTotalPaid) { @@ -3735,9 +3663,7 @@ public function setBaseTotalPaid($baseTotalPaid) } /** - * Set BaseTotalQtyOrdered - * - * @return $this + * @inheritdoc */ public function setBaseTotalQtyOrdered($baseTotalQtyOrdered) { @@ -3745,9 +3671,7 @@ public function setBaseTotalQtyOrdered($baseTotalQtyOrdered) } /** - * Set BaseTotalRefunded - * - * @return $this + * @inheritdoc */ public function setBaseTotalRefunded($baseTotalRefunded) { @@ -3755,9 +3679,7 @@ public function setBaseTotalRefunded($baseTotalRefunded) } /** - * Set DiscountAmount - * - * @return $this + * @inheritdoc */ public function setDiscountAmount($amount) { @@ -3765,9 +3687,7 @@ public function setDiscountAmount($amount) } /** - * Set DiscountCanceled - * - * @return $this + * @inheritdoc */ public function setDiscountCanceled($discountCanceled) { @@ -3775,9 +3695,7 @@ public function setDiscountCanceled($discountCanceled) } /** - * Set DiscountInvoiced - * - * @return $this + * @inheritdoc */ public function setDiscountInvoiced($discountInvoiced) { @@ -3785,9 +3703,7 @@ public function setDiscountInvoiced($discountInvoiced) } /** - * Set DiscountRefunded - * - * @return $this + * @inheritdoc */ public function setDiscountRefunded($discountRefunded) { @@ -3795,9 +3711,7 @@ public function setDiscountRefunded($discountRefunded) } /** - * Set GrandTotal - * - * @return $this + * @inheritdoc */ public function setGrandTotal($amount) { @@ -3805,9 +3719,7 @@ public function setGrandTotal($amount) } /** - * Set ShippingAmount - * - * @return $this + * @inheritdoc */ public function setShippingAmount($amount) { @@ -3815,9 +3727,7 @@ public function setShippingAmount($amount) } /** - * Set ShippingCanceled - * - * @return $this + * @inheritdoc */ public function setShippingCanceled($shippingCanceled) { @@ -3825,9 +3735,7 @@ public function setShippingCanceled($shippingCanceled) } /** - * Set ShippingInvoiced - * - * @return $this + * @inheritdoc */ public function setShippingInvoiced($shippingInvoiced) { @@ -3835,9 +3743,7 @@ public function setShippingInvoiced($shippingInvoiced) } /** - * Set ShippingRefunded - * - * @return $this + * @inheritdoc */ public function setShippingRefunded($shippingRefunded) { @@ -3845,9 +3751,7 @@ public function setShippingRefunded($shippingRefunded) } /** - * Set ShippingTaxAmount - * - * @return $this + * @inheritdoc */ public function setShippingTaxAmount($amount) { @@ -3855,9 +3759,7 @@ public function setShippingTaxAmount($amount) } /** - * Set ShippingTaxRefunded - * - * @return $this + * @inheritdoc */ public function setShippingTaxRefunded($shippingTaxRefunded) { @@ -3865,9 +3767,7 @@ public function setShippingTaxRefunded($shippingTaxRefunded) } /** - * Set StoreToBaseRate - * - * @return $this + * @inheritdoc */ public function setStoreToBaseRate($rate) { @@ -3875,9 +3775,7 @@ public function setStoreToBaseRate($rate) } /** - * Set StoreToOrderRate - * - * @return $this + * @inheritdoc */ public function setStoreToOrderRate($rate) { @@ -3885,9 +3783,7 @@ public function setStoreToOrderRate($rate) } /** - * Set Subtotal - * - * @return $this + * @inheritdoc */ public function setSubtotal($amount) { @@ -3895,9 +3791,7 @@ public function setSubtotal($amount) } /** - * Set SubtotalCanceled - * - * @return $this + * @inheritdoc */ public function setSubtotalCanceled($subtotalCanceled) { @@ -3905,9 +3799,7 @@ public function setSubtotalCanceled($subtotalCanceled) } /** - * Set SubtotalInvoiced - * - * @return $this + * @inheritdoc */ public function setSubtotalInvoiced($subtotalInvoiced) { @@ -3915,9 +3807,7 @@ public function setSubtotalInvoiced($subtotalInvoiced) } /** - * Set SubtotalRefunded - * - * @return $this + * @inheritdoc */ public function setSubtotalRefunded($subtotalRefunded) { @@ -3925,9 +3815,7 @@ public function setSubtotalRefunded($subtotalRefunded) } /** - * Set TaxAmount - * - * @return $this + * @inheritdoc */ public function setTaxAmount($amount) { @@ -3935,9 +3823,7 @@ public function setTaxAmount($amount) } /** - * Set TaxCanceled - * - * @return $this + * @inheritdoc */ public function setTaxCanceled($taxCanceled) { @@ -3945,9 +3831,7 @@ public function setTaxCanceled($taxCanceled) } /** - * Set TaxInvoiced - * - * @return $this + * @inheritdoc */ public function setTaxInvoiced($taxInvoiced) { @@ -3955,9 +3839,7 @@ public function setTaxInvoiced($taxInvoiced) } /** - * Set TaxRefunded - * - * @return $this + * @inheritdoc */ public function setTaxRefunded($taxRefunded) { @@ -3965,9 +3847,7 @@ public function setTaxRefunded($taxRefunded) } /** - * Set TotalCanceled - * - * @return $this + * @inheritdoc */ public function setTotalCanceled($totalCanceled) { @@ -3975,9 +3855,7 @@ public function setTotalCanceled($totalCanceled) } /** - * Set TotalInvoiced - * - * @return $this + * @inheritdoc */ public function setTotalInvoiced($totalInvoiced) { @@ -3985,9 +3863,7 @@ public function setTotalInvoiced($totalInvoiced) } /** - * Set TotalOfflineRefunded - * - * @return $this + * @inheritdoc */ public function setTotalOfflineRefunded($totalOfflineRefunded) { @@ -3995,9 +3871,7 @@ public function setTotalOfflineRefunded($totalOfflineRefunded) } /** - * Set TotalOnlineRefunded - * - * @return $this + * @inheritdoc */ public function setTotalOnlineRefunded($totalOnlineRefunded) { @@ -4005,9 +3879,7 @@ public function setTotalOnlineRefunded($totalOnlineRefunded) } /** - * Set TotalPaid - * - * @return $this + * @inheritdoc */ public function setTotalPaid($totalPaid) { @@ -4015,9 +3887,7 @@ public function setTotalPaid($totalPaid) } /** - * Set TotalQtyOrdered - * - * @return $this + * @inheritdoc */ public function setTotalQtyOrdered($totalQtyOrdered) { @@ -4025,9 +3895,7 @@ public function setTotalQtyOrdered($totalQtyOrdered) } /** - * Set TotalRefunded - * - * @return $this + * @inheritdoc */ public function setTotalRefunded($totalRefunded) { @@ -4035,9 +3903,7 @@ public function setTotalRefunded($totalRefunded) } /** - * Set CanShipPartially - * - * @return $this + * @inheritdoc */ public function setCanShipPartially($flag) { @@ -4045,9 +3911,7 @@ public function setCanShipPartially($flag) } /** - * Set CanShipPartiallyItem - * - * @return $this + * @inheritdoc */ public function setCanShipPartiallyItem($flag) { @@ -4055,9 +3919,7 @@ public function setCanShipPartiallyItem($flag) } /** - * Set CustomerIsGuest - * - * @return $this + * @inheritdoc */ public function setCustomerIsGuest($customerIsGuest) { @@ -4065,9 +3927,7 @@ public function setCustomerIsGuest($customerIsGuest) } /** - * Set CustomerNoteNotify - * - * @return $this + * @inheritdoc */ public function setCustomerNoteNotify($customerNoteNotify) { @@ -4075,9 +3935,7 @@ public function setCustomerNoteNotify($customerNoteNotify) } /** - * Set BillingAddressId - * - * @return $this + * @inheritdoc */ public function setBillingAddressId($id) { @@ -4085,9 +3943,7 @@ public function setBillingAddressId($id) } /** - * Set CustomerGroupId - * - * @return $this + * @inheritdoc */ public function setCustomerGroupId($id) { @@ -4095,9 +3951,7 @@ public function setCustomerGroupId($id) } /** - * Set EditIncrement - * - * @return $this + * @inheritdoc */ public function setEditIncrement($editIncrement) { @@ -4105,9 +3959,7 @@ public function setEditIncrement($editIncrement) } /** - * Set EmailSent - * - * @return $this + * @inheritdoc */ public function setEmailSent($emailSent) { @@ -4115,9 +3967,7 @@ public function setEmailSent($emailSent) } /** - * Set ForcedShipmentWithInvoice - * - * @return $this + * @inheritdoc */ public function setForcedShipmentWithInvoice($forcedShipmentWithInvoice) { @@ -4125,9 +3975,7 @@ public function setForcedShipmentWithInvoice($forcedShipmentWithInvoice) } /** - * Set PaymentAuthExpiration - * - * @return $this + * @inheritdoc */ public function setPaymentAuthExpiration($paymentAuthExpiration) { @@ -4135,9 +3983,7 @@ public function setPaymentAuthExpiration($paymentAuthExpiration) } /** - * Set QuoteAddressId - * - * @return $this + * @inheritdoc */ public function setQuoteAddressId($id) { @@ -4145,9 +3991,7 @@ public function setQuoteAddressId($id) } /** - * Set QuoteId - * - * @return $this + * @inheritdoc */ public function setQuoteId($id) { @@ -4155,9 +3999,7 @@ public function setQuoteId($id) } /** - * Set AdjustmentNegative - * - * @return $this + * @inheritdoc */ public function setAdjustmentNegative($adjustmentNegative) { @@ -4165,9 +4007,7 @@ public function setAdjustmentNegative($adjustmentNegative) } /** - * Set AdjustmentPositive - * - * @return $this + * @inheritdoc */ public function setAdjustmentPositive($adjustmentPositive) { @@ -4175,9 +4015,7 @@ public function setAdjustmentPositive($adjustmentPositive) } /** - * Set BaseAdjustmentNegative - * - * @return $this + * @inheritdoc */ public function setBaseAdjustmentNegative($baseAdjustmentNegative) { @@ -4185,9 +4023,7 @@ public function setBaseAdjustmentNegative($baseAdjustmentNegative) } /** - * Set BaseAdjustmentPositive - * - * @return $this + * @inheritdoc */ public function setBaseAdjustmentPositive($baseAdjustmentPositive) { @@ -4195,9 +4031,7 @@ public function setBaseAdjustmentPositive($baseAdjustmentPositive) } /** - * Set BaseShippingDiscountAmount - * - * @return $this + * @inheritdoc */ public function setBaseShippingDiscountAmount($amount) { @@ -4205,9 +4039,7 @@ public function setBaseShippingDiscountAmount($amount) } /** - * Set BaseSubtotalInclTax - * - * @return $this + * @inheritdoc */ public function setBaseSubtotalInclTax($amount) { @@ -4215,9 +4047,7 @@ public function setBaseSubtotalInclTax($amount) } /** - * Set BaseTotalDue - * - * @return $this + * @inheritdoc */ public function setBaseTotalDue($baseTotalDue) { @@ -4225,9 +4055,7 @@ public function setBaseTotalDue($baseTotalDue) } /** - * Set PaymentAuthorizationAmount - * - * @return $this + * @inheritdoc */ public function setPaymentAuthorizationAmount($amount) { @@ -4235,9 +4063,7 @@ public function setPaymentAuthorizationAmount($amount) } /** - * Set ShippingDiscountAmount - * - * @return $this + * @inheritdoc */ public function setShippingDiscountAmount($amount) { @@ -4245,9 +4071,7 @@ public function setShippingDiscountAmount($amount) } /** - * Set SubtotalInclTax - * - * @return $this + * @inheritdoc */ public function setSubtotalInclTax($amount) { @@ -4255,9 +4079,7 @@ public function setSubtotalInclTax($amount) } /** - * Set TotalDue - * - * @return $this + * @inheritdoc */ public function setTotalDue($totalDue) { @@ -4265,9 +4087,7 @@ public function setTotalDue($totalDue) } /** - * Set Weight - * - * @return $this + * @inheritdoc */ public function setWeight($weight) { @@ -4275,9 +4095,7 @@ public function setWeight($weight) } /** - * Set CustomerDob - * - * @return $this + * @inheritdoc */ public function setCustomerDob($customerDob) { @@ -4285,9 +4103,7 @@ public function setCustomerDob($customerDob) } /** - * Set IncrementId - * - * @return $this + * @inheritdoc */ public function setIncrementId($id) { @@ -4295,9 +4111,7 @@ public function setIncrementId($id) } /** - * Set AppliedRuleIds - * - * @return $this + * @inheritdoc */ public function setAppliedRuleIds($appliedRuleIds) { @@ -4305,9 +4119,7 @@ public function setAppliedRuleIds($appliedRuleIds) } /** - * Set BaseCurrencyCode - * - * @return $this + * @inheritdoc */ public function setBaseCurrencyCode($code) { @@ -4315,9 +4127,7 @@ public function setBaseCurrencyCode($code) } /** - * Set CustomerEmail - * - * @return $this + * @inheritdoc */ public function setCustomerEmail($customerEmail) { @@ -4325,9 +4135,7 @@ public function setCustomerEmail($customerEmail) } /** - * Set CustomerFirstname - * - * @return $this + * @inheritdoc */ public function setCustomerFirstname($customerFirstname) { @@ -4335,9 +4143,7 @@ public function setCustomerFirstname($customerFirstname) } /** - * Set CustomerLastname - * - * @return $this + * @inheritdoc */ public function setCustomerLastname($customerLastname) { @@ -4345,9 +4151,7 @@ public function setCustomerLastname($customerLastname) } /** - * Set CustomerMiddlename - * - * @return $this + * @inheritdoc */ public function setCustomerMiddlename($customerMiddlename) { @@ -4355,9 +4159,7 @@ public function setCustomerMiddlename($customerMiddlename) } /** - * Set CustomerPrefix - * - * @return $this + * @inheritdoc */ public function setCustomerPrefix($customerPrefix) { @@ -4365,9 +4167,7 @@ public function setCustomerPrefix($customerPrefix) } /** - * Set CustomerSuffix - * - * @return $this + * @inheritdoc */ public function setCustomerSuffix($customerSuffix) { @@ -4375,9 +4175,7 @@ public function setCustomerSuffix($customerSuffix) } /** - * Set CustomerTaxvat - * - * @return $this + * @inheritdoc */ public function setCustomerTaxvat($customerTaxvat) { @@ -4385,9 +4183,7 @@ public function setCustomerTaxvat($customerTaxvat) } /** - * Set DiscountDescription - * - * @return $this + * @inheritdoc */ public function setDiscountDescription($description) { @@ -4395,9 +4191,7 @@ public function setDiscountDescription($description) } /** - * Set ExtCustomerId - * - * @return $this + * @inheritdoc */ public function setExtCustomerId($id) { @@ -4405,9 +4199,7 @@ public function setExtCustomerId($id) } /** - * Set ExtOrderId - * - * @return $this + * @inheritdoc */ public function setExtOrderId($id) { @@ -4415,9 +4207,7 @@ public function setExtOrderId($id) } /** - * Set GlobalCurrencyCode - * - * @return $this + * @inheritdoc */ public function setGlobalCurrencyCode($code) { @@ -4425,9 +4215,7 @@ public function setGlobalCurrencyCode($code) } /** - * Set HoldBeforeState - * - * @return $this + * @inheritdoc */ public function setHoldBeforeState($holdBeforeState) { @@ -4435,9 +4223,7 @@ public function setHoldBeforeState($holdBeforeState) } /** - * Set HoldBeforeStatus - * - * @return $this + * @inheritdoc */ public function setHoldBeforeStatus($holdBeforeStatus) { @@ -4445,9 +4231,7 @@ public function setHoldBeforeStatus($holdBeforeStatus) } /** - * Set OrderCurrencyCode - * - * @return $this + * @inheritdoc */ public function setOrderCurrencyCode($code) { @@ -4455,9 +4239,7 @@ public function setOrderCurrencyCode($code) } /** - * Set OriginalIncrementId - * - * @return $this + * @inheritdoc */ public function setOriginalIncrementId($id) { @@ -4465,9 +4247,7 @@ public function setOriginalIncrementId($id) } /** - * Set RelationChildId - * - * @return $this + * @inheritdoc */ public function setRelationChildId($id) { @@ -4475,9 +4255,7 @@ public function setRelationChildId($id) } /** - * Set RelationChildRealId - * - * @return $this + * @inheritdoc */ public function setRelationChildRealId($realId) { @@ -4485,9 +4263,7 @@ public function setRelationChildRealId($realId) } /** - * Set RelationParentId - * - * @return $this + * @inheritdoc */ public function setRelationParentId($id) { @@ -4495,9 +4271,7 @@ public function setRelationParentId($id) } /** - * Set RelationParentRealId - * - * @return $this + * @inheritdoc */ public function setRelationParentRealId($realId) { @@ -4505,9 +4279,7 @@ public function setRelationParentRealId($realId) } /** - * Set RemoteIp - * - * @return $this + * @inheritdoc */ public function setRemoteIp($remoteIp) { @@ -4515,9 +4287,7 @@ public function setRemoteIp($remoteIp) } /** - * Set StoreCurrencyCode - * - * @return $this + * @inheritdoc */ public function setStoreCurrencyCode($code) { @@ -4525,9 +4295,7 @@ public function setStoreCurrencyCode($code) } /** - * Set StoreName - * - * @return $this + * @inheritdoc */ public function setStoreName($storeName) { @@ -4535,9 +4303,7 @@ public function setStoreName($storeName) } /** - * Set XForwardedFor - * - * @return $this + * @inheritdoc */ public function setXForwardedFor($xForwardedFor) { @@ -4545,9 +4311,7 @@ public function setXForwardedFor($xForwardedFor) } /** - * Set CustomerNote - * - * @return $this + * @inheritdoc */ public function setCustomerNote($customerNote) { @@ -4555,9 +4319,7 @@ public function setCustomerNote($customerNote) } /** - * Set UpdatedAt - * - * @return $this + * @inheritdoc */ public function setUpdatedAt($timestamp) { @@ -4565,9 +4327,7 @@ public function setUpdatedAt($timestamp) } /** - * Set TotalItemCount - * - * @return $this + * @inheritdoc */ public function setTotalItemCount($totalItemCount) { @@ -4575,9 +4335,7 @@ public function setTotalItemCount($totalItemCount) } /** - * Set CustomerGender - * - * @return $this + * @inheritdoc */ public function setCustomerGender($customerGender) { @@ -4585,9 +4343,7 @@ public function setCustomerGender($customerGender) } /** - * Set DiscountTaxCompensationAmount - * - * @return $this + * @inheritdoc */ public function setDiscountTaxCompensationAmount($amount) { @@ -4595,9 +4351,7 @@ public function setDiscountTaxCompensationAmount($amount) } /** - * Set BaseDiscountTaxCompensationAmount - * - * @return $this + * @inheritdoc */ public function setBaseDiscountTaxCompensationAmount($amount) { @@ -4605,9 +4359,7 @@ public function setBaseDiscountTaxCompensationAmount($amount) } /** - * Set ShippingDiscountTaxCompensationAmount - * - * @return $this + * @inheritdoc */ public function setShippingDiscountTaxCompensationAmount($amount) { @@ -4615,9 +4367,7 @@ public function setShippingDiscountTaxCompensationAmount($amount) } /** - * Set BaseShippingDiscountTaxCompensationAmnt - * - * @return $this + * @inheritdoc */ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) { @@ -4625,9 +4375,7 @@ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) } /** - * Set DiscountTaxCompensationInvoiced - * - * @return $this + * @inheritdoc */ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoiced) { @@ -4635,9 +4383,7 @@ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoi } /** - * Set BaseDiscountTaxCompensationInvoiced - * - * @return $this + * @inheritdoc */ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensationInvoiced) { @@ -4648,9 +4394,7 @@ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensat } /** - * Set DiscountTaxCompensationRefunded - * - * @return $this + * @inheritdoc */ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefunded) { @@ -4661,9 +4405,7 @@ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefun } /** - * Set BaseDiscountTaxCompensationRefunded - * - * @return $this + * @inheritdoc */ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensationRefunded) { @@ -4674,9 +4416,7 @@ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensat } /** - * Set ShippingInclTax - * - * @return $this + * @inheritdoc */ public function setShippingInclTax($amount) { diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php index 423d4b8d09d44..cc8bb7aae780c 100644 --- a/app/code/Magento/Sales/Model/Order/Item.php +++ b/app/code/Magento/Sales/Model/Order/Item.php @@ -651,7 +651,7 @@ public function isDummy($shipment = false) } /** - * Returns formatted buy request. + * Return formatted buy request. * * This object is holding request received from product view page with keys and options for configured product. * @@ -703,7 +703,7 @@ public function getStore() //@codeCoverageIgnoreStart /** - * Returns additional_data + * Return additional_data * * @return string|null */ @@ -713,7 +713,7 @@ public function getAdditionalData() } /** - * Returns amount_refunded + * Return amount_refunded * * @return float|null */ @@ -723,7 +723,7 @@ public function getAmountRefunded() } /** - * Returns applied_rule_ids + * Return applied_rule_ids * * @return string|null */ @@ -733,7 +733,7 @@ public function getAppliedRuleIds() } /** - * Returns base_amount_refunded + * Return base_amount_refunded * * @return float|null */ @@ -743,7 +743,7 @@ public function getBaseAmountRefunded() } /** - * Returns base_cost + * Return base_cost * * @return float|null */ @@ -753,7 +753,7 @@ public function getBaseCost() } /** - * Returns base_discount_amount + * Return base_discount_amount * * @return float|null */ @@ -763,7 +763,7 @@ public function getBaseDiscountAmount() } /** - * Returns base_discount_invoiced + * Return base_discount_invoiced * * @return float|null */ @@ -773,7 +773,7 @@ public function getBaseDiscountInvoiced() } /** - * Returns base_discount_refunded + * Return base_discount_refunded * * @return float|null */ @@ -783,7 +783,7 @@ public function getBaseDiscountRefunded() } /** - * Returns base_discount_tax_compensation_amount + * Return base_discount_tax_compensation_amount * * @return float|null */ @@ -793,7 +793,7 @@ public function getBaseDiscountTaxCompensationAmount() } /** - * Returns base_discount_tax_compensation_invoiced + * Return base_discount_tax_compensation_invoiced * * @return float|null */ @@ -803,7 +803,7 @@ public function getBaseDiscountTaxCompensationInvoiced() } /** - * Returns base_discount_tax_compensation_refunded + * Return base_discount_tax_compensation_refunded * * @return float|null */ @@ -813,7 +813,7 @@ public function getBaseDiscountTaxCompensationRefunded() } /** - * Returns base_original_price + * Return base_original_price * * @return float|null */ @@ -823,7 +823,7 @@ public function getBaseOriginalPrice() } /** - * Returns base_price + * Return base_price * * @return float|null */ @@ -833,7 +833,7 @@ public function getBasePrice() } /** - * Returns base_price_incl_tax + * Return base_price_incl_tax * * @return float|null */ @@ -843,7 +843,7 @@ public function getBasePriceInclTax() } /** - * Returns base_row_invoiced + * Return base_row_invoiced * * @return float|null */ @@ -853,7 +853,7 @@ public function getBaseRowInvoiced() } /** - * Returns base_row_total + * Return base_row_total * * @return float|null */ @@ -863,7 +863,7 @@ public function getBaseRowTotal() } /** - * Returns base_row_total_incl_tax + * Return base_row_total_incl_tax * * @return float|null */ @@ -873,7 +873,7 @@ public function getBaseRowTotalInclTax() } /** - * Returns base_tax_amount + * Return base_tax_amount * * @return float|null */ @@ -883,7 +883,7 @@ public function getBaseTaxAmount() } /** - * Returns base_tax_before_discount + * Return base_tax_before_discount * * @return float|null */ @@ -893,7 +893,7 @@ public function getBaseTaxBeforeDiscount() } /** - * Returns base_tax_invoiced + * Return base_tax_invoiced * * @return float|null */ @@ -903,7 +903,7 @@ public function getBaseTaxInvoiced() } /** - * Returns base_tax_refunded + * Return base_tax_refunded * * @return float|null */ @@ -913,7 +913,7 @@ public function getBaseTaxRefunded() } /** - * Returns base_weee_tax_applied_amount + * Return base_weee_tax_applied_amount * * @return float|null */ @@ -923,7 +923,7 @@ public function getBaseWeeeTaxAppliedAmount() } /** - * Returns base_weee_tax_applied_row_amnt + * Return base_weee_tax_applied_row_amnt * * @return float|null */ @@ -933,7 +933,7 @@ public function getBaseWeeeTaxAppliedRowAmnt() } /** - * Returns base_weee_tax_disposition + * Return base_weee_tax_disposition * * @return float|null */ @@ -943,7 +943,7 @@ public function getBaseWeeeTaxDisposition() } /** - * Returns base_weee_tax_row_disposition + * Return base_weee_tax_row_disposition * * @return float|null */ @@ -953,7 +953,7 @@ public function getBaseWeeeTaxRowDisposition() } /** - * Returns created_at + * Return created_at * * @return string|null */ @@ -971,7 +971,7 @@ public function setCreatedAt($createdAt) } /** - * Returns description + * Return description * * @return string|null */ @@ -981,7 +981,7 @@ public function getDescription() } /** - * Returns discount_amount + * Return discount_amount * * @return float|null */ @@ -991,7 +991,7 @@ public function getDiscountAmount() } /** - * Returns discount_invoiced + * Return discount_invoiced * * @return float|null */ @@ -1001,7 +1001,7 @@ public function getDiscountInvoiced() } /** - * Returns discount_percent + * Return discount_percent * * @return float|null */ @@ -1011,7 +1011,7 @@ public function getDiscountPercent() } /** - * Returns discount_refunded + * Return discount_refunded * * @return float|null */ @@ -1021,7 +1021,7 @@ public function getDiscountRefunded() } /** - * Returns event_id + * Return event_id * * @return int|null */ @@ -1031,7 +1031,7 @@ public function getEventId() } /** - * Returns ext_order_item_id + * Return ext_order_item_id * * @return string|null */ @@ -1041,7 +1041,7 @@ public function getExtOrderItemId() } /** - * Returns free_shipping + * Return free_shipping * * @return int|null */ @@ -1051,7 +1051,7 @@ public function getFreeShipping() } /** - * Returns gw_base_price + * Return gw_base_price * * @return float|null */ @@ -1061,7 +1061,7 @@ public function getGwBasePrice() } /** - * Returns gw_base_price_invoiced + * Return gw_base_price_invoiced * * @return float|null */ @@ -1071,7 +1071,7 @@ public function getGwBasePriceInvoiced() } /** - * Returns gw_base_price_refunded + * Return gw_base_price_refunded * * @return float|null */ @@ -1081,7 +1081,7 @@ public function getGwBasePriceRefunded() } /** - * Returns gw_base_tax_amount + * Return gw_base_tax_amount * * @return float|null */ @@ -1091,7 +1091,7 @@ public function getGwBaseTaxAmount() } /** - * Returns gw_base_tax_amount_invoiced + * Return gw_base_tax_amount_invoiced * * @return float|null */ @@ -1101,7 +1101,7 @@ public function getGwBaseTaxAmountInvoiced() } /** - * Returns gw_base_tax_amount_refunded + * Return gw_base_tax_amount_refunded * * @return float|null */ @@ -1111,7 +1111,7 @@ public function getGwBaseTaxAmountRefunded() } /** - * Returns gw_id + * Return gw_id * * @return int|null */ @@ -1121,7 +1121,7 @@ public function getGwId() } /** - * Returns gw_price + * Return gw_price * * @return float|null */ @@ -1131,7 +1131,7 @@ public function getGwPrice() } /** - * Returns gw_price_invoiced + * Return gw_price_invoiced * * @return float|null */ @@ -1141,7 +1141,7 @@ public function getGwPriceInvoiced() } /** - * Returns gw_price_refunded + * Return gw_price_refunded * * @return float|null */ @@ -1151,7 +1151,7 @@ public function getGwPriceRefunded() } /** - * Returns gw_tax_amount + * Return gw_tax_amount * * @return float|null */ @@ -1161,7 +1161,7 @@ public function getGwTaxAmount() } /** - * Returns gw_tax_amount_invoiced + * Return gw_tax_amount_invoiced * * @return float|null */ @@ -1171,7 +1171,7 @@ public function getGwTaxAmountInvoiced() } /** - * Returns gw_tax_amount_refunded + * Return gw_tax_amount_refunded * * @return float|null */ @@ -1181,7 +1181,7 @@ public function getGwTaxAmountRefunded() } /** - * Returns discount_tax_compensation_amount + * Return discount_tax_compensation_amount * * @return float|null */ @@ -1191,7 +1191,7 @@ public function getDiscountTaxCompensationAmount() } /** - * Returns discount_tax_compensation_canceled + * Return discount_tax_compensation_canceled * * @return float|null */ @@ -1201,7 +1201,7 @@ public function getDiscountTaxCompensationCanceled() } /** - * Returns discount_tax_compensation_invoiced + * Return discount_tax_compensation_invoiced * * @return float|null */ @@ -1211,7 +1211,7 @@ public function getDiscountTaxCompensationInvoiced() } /** - * Returns discount_tax_compensation_refunded + * Return discount_tax_compensation_refunded * * @return float|null */ @@ -1221,7 +1221,7 @@ public function getDiscountTaxCompensationRefunded() } /** - * Returns is_qty_decimal + * Return is_qty_decimal * * @return int|null */ @@ -1231,7 +1231,7 @@ public function getIsQtyDecimal() } /** - * Returns is_virtual + * Return is_virtual * * @return int|null */ @@ -1241,7 +1241,7 @@ public function getIsVirtual() } /** - * Returns item_id + * Return item_id * * @return int|null */ @@ -1251,7 +1251,7 @@ public function getItemId() } /** - * Returns locked_do_invoice + * Return locked_do_invoice * * @return int|null */ @@ -1261,7 +1261,7 @@ public function getLockedDoInvoice() } /** - * Returns locked_do_ship + * Return locked_do_ship * * @return int|null */ @@ -1271,7 +1271,7 @@ public function getLockedDoShip() } /** - * Returns name + * Return name * * @return string|null */ @@ -1281,7 +1281,7 @@ public function getName() } /** - * Returns no_discount + * Return no_discount * * @return int|null */ @@ -1291,7 +1291,7 @@ public function getNoDiscount() } /** - * Returns order_id + * Return order_id * * @return int|null */ @@ -1301,7 +1301,7 @@ public function getOrderId() } /** - * Returns parent_item_id + * Return parent_item_id * * @return int|null */ @@ -1311,7 +1311,7 @@ public function getParentItemId() } /** - * Returns price + * Return price * * @return float|null */ @@ -1321,7 +1321,7 @@ public function getPrice() } /** - * Returns price_incl_tax + * Return price_incl_tax * * @return float|null */ @@ -1331,7 +1331,7 @@ public function getPriceInclTax() } /** - * Returns product_id + * Return product_id * * @return int|null */ @@ -1341,7 +1341,7 @@ public function getProductId() } /** - * Returns product_type + * Return product_type * * @return string|null */ @@ -1351,7 +1351,7 @@ public function getProductType() } /** - * Returns qty_backordered + * Return qty_backordered * * @return float|null */ @@ -1361,7 +1361,7 @@ public function getQtyBackordered() } /** - * Returns qty_canceled + * Return qty_canceled * * @return float|null */ @@ -1371,7 +1371,7 @@ public function getQtyCanceled() } /** - * Returns qty_invoiced + * Return qty_invoiced * * @return float|null */ @@ -1381,7 +1381,7 @@ public function getQtyInvoiced() } /** - * Returns qty_ordered + * Return qty_ordered * * @return float|null */ @@ -1391,7 +1391,7 @@ public function getQtyOrdered() } /** - * Returns qty_refunded + * Return qty_refunded * * @return float|null */ @@ -1401,7 +1401,7 @@ public function getQtyRefunded() } /** - * Returns qty_returned + * Return qty_returned * * @return float|null */ @@ -1411,7 +1411,7 @@ public function getQtyReturned() } /** - * Returns qty_shipped + * Return qty_shipped * * @return float|null */ @@ -1421,7 +1421,7 @@ public function getQtyShipped() } /** - * Returns quote_item_id + * Return quote_item_id * * @return int|null */ @@ -1431,7 +1431,7 @@ public function getQuoteItemId() } /** - * Returns row_invoiced + * Return row_invoiced * * @return float|null */ @@ -1441,7 +1441,7 @@ public function getRowInvoiced() } /** - * Returns row_total + * Return row_total * * @return float|null */ @@ -1451,7 +1451,7 @@ public function getRowTotal() } /** - * Returns row_total_incl_tax + * Return row_total_incl_tax * * @return float|null */ @@ -1461,7 +1461,7 @@ public function getRowTotalInclTax() } /** - * Returns row_weight + * Return row_weight * * @return float|null */ @@ -1471,7 +1471,7 @@ public function getRowWeight() } /** - * Returns sku + * Return sku * * @return string */ @@ -1481,7 +1481,7 @@ public function getSku() } /** - * Returns store_id + * Return store_id * * @return int|null */ @@ -1491,7 +1491,7 @@ public function getStoreId() } /** - * Returns tax_amount + * Return tax_amount * * @return float|null */ @@ -1501,7 +1501,7 @@ public function getTaxAmount() } /** - * Returns tax_before_discount + * Return tax_before_discount * * @return float|null */ @@ -1511,7 +1511,7 @@ public function getTaxBeforeDiscount() } /** - * Returns tax_canceled + * Return tax_canceled * * @return float|null */ @@ -1521,7 +1521,7 @@ public function getTaxCanceled() } /** - * Returns tax_invoiced + * Return tax_invoiced * * @return float|null */ @@ -1531,7 +1531,7 @@ public function getTaxInvoiced() } /** - * Returns tax_percent + * Return tax_percent * * @return float|null */ @@ -1541,7 +1541,7 @@ public function getTaxPercent() } /** - * Returns tax_refunded + * Return tax_refunded * * @return float|null */ @@ -1551,7 +1551,7 @@ public function getTaxRefunded() } /** - * Returns updated_at + * Return updated_at * * @return string|null */ @@ -1561,7 +1561,7 @@ public function getUpdatedAt() } /** - * Returns weee_tax_applied + * Return weee_tax_applied * * @return string|null */ @@ -1571,7 +1571,7 @@ public function getWeeeTaxApplied() } /** - * Returns weee_tax_applied_amount + * Return weee_tax_applied_amount * * @return float|null */ @@ -1581,7 +1581,7 @@ public function getWeeeTaxAppliedAmount() } /** - * Returns weee_tax_applied_row_amount + * Return weee_tax_applied_row_amount * * @return float|null */ @@ -1591,7 +1591,7 @@ public function getWeeeTaxAppliedRowAmount() } /** - * Returns weee_tax_disposition + * Return weee_tax_disposition * * @return float|null */ @@ -1601,7 +1601,7 @@ public function getWeeeTaxDisposition() } /** - * Returns weee_tax_row_disposition + * Return weee_tax_row_disposition * * @return float|null */ @@ -1611,7 +1611,7 @@ public function getWeeeTaxRowDisposition() } /** - * Returns weight + * Return weight * * @return float|null */ From d0840536ed651a94bc684489a57207ce34048545 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 17 Sep 2018 16:04:01 -0500 Subject: [PATCH 039/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Controller/Adminhtml/Product/Attribute/Save.php | 2 +- .../Controller/Adminhtml/Product/Attribute/Validate.php | 2 +- .../Mftf/Test/AdminEditTextEditorProductAttributeTest.xml | 7 +++---- .../Controller/Adminhtml/Product/Attribute/SaveTest.php | 6 +++--- .../Adminhtml/Product/Attribute/ValidateTest.php | 8 ++++---- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index e32d84b393aeb..e730381b0ea58 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -140,7 +140,7 @@ public function execute() { try { $optionData = $this->optionsDataSerializer - ->unserialize($this->getRequest()->getParam('serialized_options')); + ->unserialize($this->getRequest()->getParam('serialized_options', '[]')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " . "If the error persists, please try again later."); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index 34dcf6639f943..16449762b4a7b 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -83,7 +83,7 @@ public function execute() $response->setError(false); try { $optionsData = $this->optionsDataSerializer - ->unserialize($this->getRequest()->getParam('serialized_options')); + ->unserialize($this->getRequest()->getParam('serialized_options', '[]')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be validated due to an error. Verify your information and try again. " . "If the error persists, please try again later."); diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml index 7603400ba8dcd..e914b8c96d03e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml @@ -26,10 +26,9 @@ <requiredEntity createDataKey="myProductAttributeCreation"/> </createData> </before> - <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid1"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <click selector="{{AdminProductAttributeGridSection.AttributeCode($$myProductAttributeCreation.attribute_code$$)}}" stepKey="navigateToAttributeEditPage1" /> - <waitForPageLoad stepKey="waitForPageLoad2" /> + <actionGroup ref="navigateToCreatedProductAttribute" stepKey="navigateToAttribute"> + <argument name="ProductAttribute" value="productAttributeWysiwyg"/> + </actionGroup> <seeOptionIsSelected selector="{{AttributePropertiesSection.InputType}}" userInput="Text Editor" stepKey="seeTextEditorSelected" /> <see selector="{{AttributePropertiesSection.InputType}}" userInput="Text Area" stepKey="seeTextArea1" /> <selectOption selector="{{AttributePropertiesSection.InputType}}" userInput="Text Area" stepKey="selectTextArea" /> diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php index b9b1aeb9157db..f34a70260a2e0 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php @@ -180,7 +180,7 @@ public function testExecuteWithEmptyData() ->method('getParam') ->willReturnMap([ ['isAjax', null, null], - ['serialized_options', null, ''], + ['serialized_options', '[]', ''], ]); $this->optionsDataSerializerMock ->expects($this->once()) @@ -211,7 +211,7 @@ public function testExecute() ->method('getParam') ->willReturnMap([ ['isAjax', null, null], - ['serialized_options', null, ''], + ['serialized_options', '[]', ''], ]); $this->optionsDataSerializerMock ->expects($this->once()) @@ -271,7 +271,7 @@ public function testExecuteWithOptionsDataError() ->method('getParam') ->willReturnMap([ ['isAjax', null, true], - ['serialized_options', null, $serializedOptions], + ['serialized_options', '[]', $serializedOptions], ]); $this->optionsDataSerializerMock ->expects($this->once()) diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php index e9fc8bf3362b3..17af610fed76c 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php @@ -130,7 +130,7 @@ public function testExecute() ['frontend_label', null, 'test_frontend_label'], ['attribute_code', null, 'test_attribute_code'], ['new_attribute_set_name', null, 'test_attribute_set_name'], - ['serialized_options', null, $serializedOptions], + ['serialized_options', '[]', $serializedOptions], ]); $this->objectManagerMock->expects($this->exactly(2)) ->method('create') @@ -181,7 +181,7 @@ public function testUniqueValidation(array $options, $isError) ['attribute_code', null, "test_attribute_code"], ['new_attribute_set_name', null, 'test_attribute_set_name'], ['message_key', null, Validate::DEFAULT_MESSAGE_KEY], - ['serialized_options', null, $serializedOptions], + ['serialized_options', '[]', $serializedOptions], ]); $this->optionsDataSerializerMock @@ -316,7 +316,7 @@ public function testEmptyOption(array $options, $result) ['attribute_code', null, "test_attribute_code"], ['new_attribute_set_name', null, 'test_attribute_set_name'], ['message_key', Validate::DEFAULT_MESSAGE_KEY, 'message'], - ['serialized_options', null, $serializedOptions], + ['serialized_options', '[]', $serializedOptions], ]); $this->optionsDataSerializerMock @@ -428,7 +428,7 @@ public function testExecuteWithOptionsDataError() ['attribute_code', null, 'test_attribute_code'], ['new_attribute_set_name', null, 'test_attribute_set_name'], ['message_key', Validate::DEFAULT_MESSAGE_KEY, 'message'], - ['serialized_options', null, $serializedOptions], + ['serialized_options', '[]', $serializedOptions], ]); $this->optionsDataSerializerMock From d1cbcc0e238fe7328c1af2b504908ec6473a1435 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 17 Sep 2018 16:42:37 -0500 Subject: [PATCH 040/118] MAGETWO-94819: Swatch validation breaks the whole attribute form -- fix merge conflict --- .../Adminhtml/Product/Attribute/Validate.php | 5 ++++- .../Adminhtml/Product/AttributeTest.php | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index 16449762b4a7b..d9627ddd1476d 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -8,15 +8,18 @@ namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; +use Magento\Catalog\Controller\Adminhtml\Product\Attribute as AttributeAction; /** * Product attribute validate controller. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute +class Validate extends AttributeAction implements HttpGetActionInterface, HttpPostActionInterface { const DEFAULT_MESSAGE_KEY = 'message'; diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php index 1a0073b154ffa..36e216ab4e57e 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php @@ -7,6 +7,8 @@ namespace Magento\Swatches\Controller\Adminhtml\Product; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Data\Form\FormKey; use Magento\Framework\Exception\LocalizedException; /** @@ -17,6 +19,21 @@ */ class AttributeTest extends \Magento\TestFramework\TestCase\AbstractBackendController { + /** + * @var FormKey + */ + private $formKey; + + /** + * @inheritDoc + */ + protected function setUp() + { + parent::setUp(); + + $this->formKey = $this->_objectManager->get(FormKey::class); + } + /** * Generate random hex color. * @@ -116,6 +133,7 @@ private function getAttributePreset() : array { return [ 'form_key' => 'XxtpPYjm2YPYUlAt', + 'serialized_options' => '[]', 'frontend_label' => [ 0 => 'asdasd', 1 => '', @@ -178,7 +196,9 @@ public function testLargeOptionsDataSet( int $expectedOptionsCount, array $expectedLabels ) : void { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); $this->getRequest()->setPostValue($attributeData); + $this->getRequest()->setPostValue('form_key', $this->formKey->getFormKey()); $this->dispatch('backend/catalog/product_attribute/save'); $entityTypeId = $this->_objectManager->create( \Magento\Eav\Model\Entity::class From a00e05588001e9e50c26d3902b416f24e756019a Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Tue, 18 Sep 2018 09:07:00 -0500 Subject: [PATCH 041/118] MAGETWO-90540: MFTF Test failure - Advanced Reporting configuration permission --- .../Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml | 3 --- .../Test/Mftf/Test/AdminConfigurationIndustryTest.xml | 3 --- 2 files changed, 6 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml index d9617209dcdff..1706383fc7866 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml @@ -16,9 +16,6 @@ <severity value="MAJOR"/> <testCaseId value="MAGETWO-66465"/> <group value="analytics"/> - <skip> - <issueId value="MAGETWO-90659"/> - </skip> </annotations> <after> <amOnPage stepKey="amOnLogoutPage" url="admin/admin/auth/logout/"/> diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml index 2d5594a43b1a7..dcfdca9e8edd7 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml @@ -17,9 +17,6 @@ <severity value="MAJOR"/> <testCaseId value="MAGETWO-63898"/> <group value="analytics"/> - <skip> - <issueId value="MAGETWO-90659"/> - </skip> </annotations> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> From b33c4b2ccfb71a4ed126749698a530330fa8aab8 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Tue, 18 Sep 2018 13:56:47 -0500 Subject: [PATCH 042/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Adminhtml/Product/Attribute/Save.php | 16 +++--- .../Adminhtml/Product/Attribute/Validate.php | 16 +++--- .../Option/OptionsDataSerializer.php | 50 ----------------- .../Adminhtml/Product/Attribute/SaveTest.php | 16 +++--- .../Product/Attribute/ValidateTest.php | 16 +++--- .../Serialize/Serializer/FormData.php | 53 +++++++++++++++++++ 6 files changed, 85 insertions(+), 82 deletions(-) delete mode 100644 app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php create mode 100644 lib/internal/Magento/Framework/Serialize/Serializer/FormData.php diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index bf60381a8a4e7..435fdb0b41301 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -14,7 +14,7 @@ use Magento\Catalog\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Helper\Product; use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; +use Magento\Framework\Serialize\Serializer\FormData; use Magento\Catalog\Model\Product\AttributeSet\BuildFactory; use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory; use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator; @@ -80,9 +80,9 @@ class Save extends Attribute implements HttpPostActionInterface private $presentation; /** - * @var OptionsDataSerializer|null + * @var FormData|null */ - private $optionsDataSerializer; + private $dataSerializer; /** * @param Context $context @@ -97,7 +97,7 @@ class Save extends Attribute implements HttpPostActionInterface * @param Product $productHelper * @param LayoutFactory $layoutFactory * @param Presentation|null $presentation - * @param OptionsDataSerializer|null $optionsDataSerializer + * @param FormData|null $dataSerializer * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -113,7 +113,7 @@ public function __construct( Product $productHelper, LayoutFactory $layoutFactory, Presentation $presentation = null, - OptionsDataSerializer $optionsDataSerializer = null + FormData $dataSerializer = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->buildFactory = $buildFactory; @@ -124,8 +124,8 @@ public function __construct( $this->groupCollectionFactory = $groupCollectionFactory; $this->layoutFactory = $layoutFactory; $this->presentation = $presentation ?: ObjectManager::getInstance()->get(Presentation::class); - $this->optionsDataSerializer = $optionsDataSerializer - ?: ObjectManager::getInstance()->get(OptionsDataSerializer::class); + $this->dataSerializer = $dataSerializer + ?: ObjectManager::getInstance()->get(FormData::class); } /** @@ -140,7 +140,7 @@ public function __construct( public function execute() { try { - $optionData = $this->optionsDataSerializer + $optionData = $this->dataSerializer ->unserialize($this->getRequest()->getParam('serialized_options', '[]')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index d9627ddd1476d..4e33fc737f0c4 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -7,7 +7,7 @@ namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; +use Magento\Framework\Serialize\Serializer\FormData; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; use Magento\Framework\App\ObjectManager; @@ -39,9 +39,9 @@ class Validate extends AttributeAction implements HttpGetActionInterface, HttpPo private $multipleAttributeList; /** - * @var OptionsDataSerializer|null + * @var FormData|null */ - private $optionsDataSerializer; + private $dataSerializer; /** * Constructor @@ -53,7 +53,7 @@ class Validate extends AttributeAction implements HttpGetActionInterface, HttpPo * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\View\LayoutFactory $layoutFactory * @param array $multipleAttributeList - * @param OptionsDataSerializer|null $optionsDataSerializer + * @param FormData|null $dataSerializer */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -63,14 +63,14 @@ public function __construct( \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, \Magento\Framework\View\LayoutFactory $layoutFactory, array $multipleAttributeList = [], - OptionsDataSerializer $optionsDataSerializer = null + FormData $dataSerializer = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; $this->multipleAttributeList = $multipleAttributeList; - $this->optionsDataSerializer = $optionsDataSerializer ?: ObjectManager::getInstance() - ->get(OptionsDataSerializer::class); + $this->dataSerializer = $dataSerializer ?: ObjectManager::getInstance() + ->get(FormData::class); } /** @@ -85,7 +85,7 @@ public function execute() $response = new DataObject(); $response->setError(false); try { - $optionsData = $this->optionsDataSerializer + $optionsData = $this->dataSerializer ->unserialize($this->getRequest()->getParam('serialized_options', '[]')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be validated due to an error. Verify your information and try again. " diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php b/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php deleted file mode 100644 index 8fe02a9123b18..0000000000000 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Option/OptionsDataSerializer.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -declare(strict_types=1); - -namespace Magento\Catalog\Model\Product\Attribute\Option; - -use Magento\Framework\Serialize\SerializerInterface; - -/** - * Attribute options data serializer. - */ -class OptionsDataSerializer -{ - /** - * @var SerializerInterface - */ - private $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) - { - $this->serializer = $serializer; - } - - /** - * Provides attribute options data from the serialized data. - * - * @param string $serializedOptions - * @return array - */ - public function unserialize(string $serializedOptions): array - { - $optionsData = []; - $encodedOptions = $this->serializer->unserialize($serializedOptions); - - foreach ($encodedOptions as $encodedOption) { - $decodedOptionData = []; - parse_str($encodedOption, $decodedOptionData); - $optionsData = array_replace_recursive($optionsData, $decodedOptionData); - } - - return $optionsData; - } -} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php index f34a70260a2e0..e73f3527517f8 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php @@ -7,7 +7,7 @@ use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Catalog\Controller\Adminhtml\Product\Attribute\Save; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; +use Magento\Framework\Serialize\Serializer\FormData; use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest; use Magento\Catalog\Model\Product\AttributeSet\BuildFactory; use Magento\Catalog\Model\Product\AttributeSet\Build; @@ -85,9 +85,9 @@ class SaveTest extends AttributeTest protected $inputTypeValidatorMock; /** - * @var OptionsDataSerializer|\PHPUnit_Framework_MockObject_MockObject + * @var FormData|\PHPUnit_Framework_MockObject_MockObject */ - private $optionsDataSerializerMock; + private $dataSerializerMock; /** * @var ProductAttributeInterface|\PHPUnit_Framework_MockObject_MockObject @@ -135,7 +135,7 @@ protected function setUp() $this->inputTypeValidatorMock = $this->getMockBuilder(InputTypeValidator::class) ->disableOriginalConstructor() ->getMock(); - $this->optionsDataSerializerMock = $this->getMockBuilder(OptionsDataSerializer::class) + $this->dataSerializerMock = $this->getMockBuilder(FormData::class) ->disableOriginalConstructor() ->getMock(); $this->productAttributeMock = $this->getMockBuilder(ProductAttributeInterface::class) @@ -170,7 +170,7 @@ protected function getModel() 'validatorFactory' => $this->validatorFactoryMock, 'groupCollectionFactory' => $this->groupCollectionFactoryMock, 'layoutFactory' => $this->layoutFactoryMock, - 'optionsDataSerializer' => $this->optionsDataSerializerMock, + 'dataSerializer' => $this->dataSerializerMock, ]); } @@ -182,7 +182,7 @@ public function testExecuteWithEmptyData() ['isAjax', null, null], ['serialized_options', '[]', ''], ]); - $this->optionsDataSerializerMock + $this->dataSerializerMock ->expects($this->once()) ->method('unserialize') ->with('') @@ -213,7 +213,7 @@ public function testExecute() ['isAjax', null, null], ['serialized_options', '[]', ''], ]); - $this->optionsDataSerializerMock + $this->dataSerializerMock ->expects($this->once()) ->method('unserialize') ->with('') @@ -273,7 +273,7 @@ public function testExecuteWithOptionsDataError() ['isAjax', null, true], ['serialized_options', '[]', $serializedOptions], ]); - $this->optionsDataSerializerMock + $this->dataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php index 17af610fed76c..666e6c1942c7a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php @@ -6,7 +6,7 @@ namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Attribute; use Magento\Catalog\Controller\Adminhtml\Product\Attribute\Validate; -use Magento\Catalog\Model\Product\Attribute\Option\OptionsDataSerializer; +use Magento\Framework\Serialize\Serializer\FormData; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest; use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet; @@ -63,9 +63,9 @@ class ValidateTest extends AttributeTest protected $layoutMock; /** - * @var OptionsDataSerializer|\PHPUnit_Framework_MockObject_MockObject + * @var FormData|\PHPUnit_Framework_MockObject_MockObject */ - private $optionsDataSerializerMock; + private $dataSerializerMock; protected function setUp() { @@ -92,7 +92,7 @@ protected function setUp() ->getMock(); $this->layoutMock = $this->getMockBuilder(LayoutInterface::class) ->getMockForAbstractClass(); - $this->optionsDataSerializerMock = $this->getMockBuilder(OptionsDataSerializer::class) + $this->dataSerializerMock = $this->getMockBuilder(FormData::class) ->disableOriginalConstructor() ->getMock(); @@ -116,7 +116,7 @@ protected function getModel() 'resultJsonFactory' => $this->resultJsonFactoryMock, 'layoutFactory' => $this->layoutFactoryMock, 'multipleAttributeList' => ['select' => 'option'], - 'optionsDataSerializer' => $this->optionsDataSerializerMock, + 'dataSerializer' => $this->dataSerializerMock, ] ); } @@ -184,7 +184,7 @@ public function testUniqueValidation(array $options, $isError) ['serialized_options', '[]', $serializedOptions], ]); - $this->optionsDataSerializerMock + $this->dataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) @@ -319,7 +319,7 @@ public function testEmptyOption(array $options, $result) ['serialized_options', '[]', $serializedOptions], ]); - $this->optionsDataSerializerMock + $this->dataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) @@ -431,7 +431,7 @@ public function testExecuteWithOptionsDataError() ['serialized_options', '[]', $serializedOptions], ]); - $this->optionsDataSerializerMock + $this->dataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) diff --git a/lib/internal/Magento/Framework/Serialize/Serializer/FormData.php b/lib/internal/Magento/Framework/Serialize/Serializer/FormData.php new file mode 100644 index 0000000000000..a945822d92f97 --- /dev/null +++ b/lib/internal/Magento/Framework/Serialize/Serializer/FormData.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\Serialize\Serializer; + +/** + * Class for processing of serialized form data. + */ +class FormData +{ + /** + * @var Json + */ + private $serializer; + + /** + * @param Json $serializer + */ + public function __construct(Json $serializer) + { + $this->serializer = $serializer; + } + + /** + * Provides form data from the serialized data. + * + * @param string $serializedData + * @return array + * @throws \InvalidArgumentException + */ + public function unserialize(string $serializedData): array + { + $encodedFields = $this->serializer->unserialize($serializedData); + + if (!is_array($encodedFields)) { + throw new \InvalidArgumentException('Unable to unserialize value.'); + } + + $formData = []; + foreach ($encodedFields as $item) { + $decodedFieldData = []; + parse_str($item, $decodedFieldData); + $formData = array_replace_recursive($formData, $decodedFieldData); + } + + return $formData; + } +} From 1407b93a6d450c22c96b5829dcb10809d78035e8 Mon Sep 17 00:00:00 2001 From: Joan He <johe@magento.com> Date: Tue, 18 Sep 2018 14:53:02 -0500 Subject: [PATCH 043/118] MAGETWO-90540: MFTF Test failure - Advanced Reporting configuration permission --- app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml | 4 ++-- .../{Analytics => User}/Test/Mftf/Metadata/user-meta.xml | 0 .../{Analytics => User}/Test/Mftf/Metadata/user_role-meta.xml | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename app/code/Magento/{Analytics => User}/Test/Mftf/Metadata/user-meta.xml (100%) rename app/code/Magento/{Analytics => User}/Test/Mftf/Metadata/user_role-meta.xml (100%) diff --git a/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml b/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml index f6e5b955816e2..83f27def4b4e8 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="adminNoReport" type="user"> <data key="username" unique="suffix">noreport</data> <data key="firstname">No</data> @@ -18,7 +18,7 @@ <data key="interface_local">en_US</data> <data key="is_active">true</data> <data key="current_password">123123q</data> -</entity> + </entity> <entity name="restrictedWebUser" type="user"> <data key="username" unique="suffix">restrictedWebUser</data> <data key="firstname">restricted</data> diff --git a/app/code/Magento/Analytics/Test/Mftf/Metadata/user-meta.xml b/app/code/Magento/User/Test/Mftf/Metadata/user-meta.xml similarity index 100% rename from app/code/Magento/Analytics/Test/Mftf/Metadata/user-meta.xml rename to app/code/Magento/User/Test/Mftf/Metadata/user-meta.xml diff --git a/app/code/Magento/Analytics/Test/Mftf/Metadata/user_role-meta.xml b/app/code/Magento/User/Test/Mftf/Metadata/user_role-meta.xml similarity index 100% rename from app/code/Magento/Analytics/Test/Mftf/Metadata/user_role-meta.xml rename to app/code/Magento/User/Test/Mftf/Metadata/user_role-meta.xml From 9cc36ea63c739048e9e55513784bf3aabcba0a45 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Tue, 18 Sep 2018 16:33:23 -0500 Subject: [PATCH 044/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Test/Mftf/Section/AdminCreateProductAttributeSection.xml | 1 + .../Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml | 5 +++++ .../Catalog/Controller/Adminhtml/Product/AttributeTest.php | 1 - .../Swatches/Controller/Adminhtml/Product/AttributeTest.php | 1 - 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml index a497233afbd4e..17778c76da9b9 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml @@ -24,6 +24,7 @@ <element name="useInLayeredNavigation" type="select" selector="#is_filterable"/> </section> <section name="StorefrontPropertiesSection"> + <element name="PageTitle" type="text" selector="//span[text()='Storefront Properties']" /> <element name="StoreFrontPropertiesTab" selector="#product_attribute_tabs_front" type="button"/> <element name="EnableWYSIWYG" type="select" selector="#enabled"/> <element name="useForPromoRuleConditions" type="select" selector="#is_used_for_promo_rules"/> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml index 1e9ce849db1be..50dcfbf3da090 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchWithNonValidOptionsTest.xml @@ -66,6 +66,11 @@ <fillField selector="{{AdminManageSwatchSection.adminInputByIndex('0')}}" userInput="red" stepKey="fillAdmin1"/> + <!-- Go to Storefront Properties tab --> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click selector="{{StorefrontPropertiesSection.StoreFrontPropertiesTab}}" stepKey="goToStorefrontPropertiesTab"/> + <waitForElementVisible selector="{{StorefrontPropertiesSection.PageTitle}}" stepKey="waitTabLoad"/> + <!-- Save the new product attribute --> <click selector="{{AttributePropertiesSection.Save}}" stepKey="clickSave2"/> <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php index 5a1dcae6cb0c4..1f70ad0f7df6b 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php @@ -392,7 +392,6 @@ protected function _getAttributeData() 'used_for_sort_by' => '0', 'apply_to' => ['simple'], 'frontend_label' => [\Magento\Store\Model\Store::DEFAULT_STORE_ID => 'string to translate'], - 'serialized_options' => '[]', ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php index 36e216ab4e57e..5b7a80bb38dfd 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Controller/Adminhtml/Product/AttributeTest.php @@ -133,7 +133,6 @@ private function getAttributePreset() : array { return [ 'form_key' => 'XxtpPYjm2YPYUlAt', - 'serialized_options' => '[]', 'frontend_label' => [ 0 => 'asdasd', 1 => '', From 9793fb17167618d4f86316a2110cbd0f52e8ce15 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Wed, 19 Sep 2018 14:43:08 +0300 Subject: [PATCH 045/118] MAGETWO-92195: Wrong order request flow --- .../Sales/Controller/Adminhtml/Order/MassHold.php | 3 ++- .../Sales/Controller/Adminhtml/Order/MassUnhold.php | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php index 241255f68e39f..5c96fbbe9e247 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php @@ -5,6 +5,7 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; @@ -14,7 +15,7 @@ /** * Class MassHold */ -class MassHold extends \Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction +class MassHold extends \Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php index 5e8ea9c4ad071..bd377e40f1849 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php @@ -5,13 +5,19 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Sales\Model\ResourceModel\Order\CollectionFactory; use Magento\Sales\Api\OrderManagementInterface; -class MassUnhold extends AbstractMassAction +/** + * Class MassUnhold + * + * @package Magento\Sales\Controller\Adminhtml\Order + */ +class MassUnhold extends AbstractMassAction implements HttpPostActionInterface { /** * Authorization level of a basic admin session @@ -24,6 +30,8 @@ class MassUnhold extends AbstractMassAction private $orderManagement; /** + * Class constructor + * * @param Context $context * @param Filter $filter * @param CollectionFactory $collectionFactory From c450f44eeb530881115d63857f9d7e6af6f97158 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Wed, 19 Sep 2018 14:46:20 +0300 Subject: [PATCH 046/118] MAGETWO-92195: Wrong order request flow --- .../Adminhtml/Order/MassCancelTest.php | 294 ------------------ .../Adminhtml/Order/MassHoldTest.php | 262 ---------------- .../Adminhtml/Order/MassUnholdTest.php | 261 ---------------- 3 files changed, 817 deletions(-) delete mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php delete mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php delete mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php deleted file mode 100644 index 38449c5686631..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php +++ /dev/null @@ -1,294 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Sales\Test\Unit\Controller\Adminhtml\Order; - -use Magento\Framework\App\Action\Context; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; - -/** - * Class MassCancelTest - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class MassCancelTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Sales\Controller\Adminhtml\Order\MassCancel - */ - protected $massAction; - - /** - * @var Context|\PHPUnit_Framework_MockObject_MockObject - */ - protected $contextMock; - - /** - * @var \Magento\Backend\Model\View\Result\Redirect|\PHPUnit_Framework_MockObject_MockObject - */ - protected $resultRedirectMock; - - /** - * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject - */ - protected $requestMock; - - /** - * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $responseMock; - - /** - * @var \Magento\Framework\Message\Manager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $messageManagerMock; - - /** - * @var \Magento\Framework\ObjectManager\ObjectManager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $objectManagerMock; - - /** - * @var \Magento\Backend\Model\Session|\PHPUnit_Framework_MockObject_MockObject - */ - protected $sessionMock; - - /** - * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject - */ - protected $actionFlagMock; - - /** - * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject - */ - protected $helperMock; - - /** - * @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderMock; - - /** - * @var \Magento\Sales\Model\ResourceModel\Order\Collection|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderCollectionMock; - - /** - * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderCollectionFactoryMock; - - /** - * @var \Magento\Ui\Component\MassAction\Filter|\PHPUnit_Framework_MockObject_MockObject - */ - protected $filterMock; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $orderManagementMock; - - /** - * Test setup - */ - protected function setUp() - { - $objectManagerHelper = new ObjectManagerHelper($this); - $this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); - $this->responseMock = $this->createMock(\Magento\Framework\App\ResponseInterface::class); - $this->requestMock = $this->createMock(\Magento\Framework\App\Request\Http::class); - $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManager\ObjectManager::class); - - $resultRedirectFactory = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); - - $this->orderCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - - $resourceCollection = \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class; - $this->orderCollectionFactoryMock = $this->getMockBuilder($resourceCollection) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->sessionMock = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); - $this->actionFlagMock = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get', 'set']); - $this->helperMock = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); - $this->resultRedirectMock = $this->createMock(\Magento\Backend\Model\View\Result\Redirect::class); - $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirectMock); - - $redirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $resultFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $resultFactoryMock->expects($this->any()) - ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($redirectMock); - - $this->contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); - $this->contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock); - $this->contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock); - $this->contextMock->expects($this->once()) - ->method('getResultRedirectFactory') - ->willReturn($resultRedirectFactory); - $this->contextMock->expects($this->any()) - ->method('getResultFactory') - ->willReturn($resultFactoryMock); - $this->filterMock = $this->createMock(\Magento\Ui\Component\MassAction\Filter::class); - $this->filterMock->expects($this->once()) - ->method('getCollection') - ->with($this->orderCollectionMock) - ->willReturn($this->orderCollectionMock); - $this->orderCollectionFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->orderCollectionMock); - $this->orderManagementMock = $this->createMock(\Magento\Sales\Api\OrderManagementInterface::class); - - $this->massAction = $objectManagerHelper->getObject( - \Magento\Sales\Controller\Adminhtml\Order\MassCancel::class, - [ - 'context' => $this->contextMock, - 'filter' => $this->filterMock, - 'collectionFactory' => $this->orderCollectionFactoryMock, - 'orderManagement' => $this->orderManagementMock - ] - ); - } - - /** - * Test for selected orders - * Two orders, only $order1 can be canceled - */ - public function testExecuteCanCancelOneOrder() - { - $order1id = 100; - $order2id = 200; - - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('getEntityId') - ->willReturn($order1id); - - $order2->expects($this->once()) - ->method('getEntityId') - ->willReturn($order2id); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $this->orderManagementMock->expects($this->at(0))->method('cancel')->with($order1id)->willReturn(true); - $this->orderManagementMock->expects($this->at(1))->method('cancel')->with($order2id)->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('1 order(s) cannot be canceled.'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccessMessage') - ->with('We canceled 1 order(s).'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - /** - * Test for excluded orders - * Two orders could't be canceled - */ - public function testExcludedCannotCancelOrders() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $order1->expects($this->once()) - ->method('getEntityId') - ->willReturn(100); - - $order2->expects($this->once()) - ->method('getEntityId') - ->willReturn(200); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn([$order1, $order2]); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $this->orderManagementMock->expects($this->atLeastOnce())->method('cancel')->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('You cannot cancel the order(s).'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - /** - * Order throws exception while canceling - */ - public function testException() - { - $exception = new \Exception('Can not cancel'); - - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn([$order1]); - - $order1->expects($this->once()) - ->method('getEntityId') - ->willReturn(100); - - $this->orderManagementMock->expects($this->atLeastOnce())->method('cancel')->willThrowException($exception); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('Can not cancel'); - - $this->massAction->execute(); - } -} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php deleted file mode 100644 index bfd1d1e825f89..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php +++ /dev/null @@ -1,262 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Sales\Test\Unit\Controller\Adminhtml\Order; - -use Magento\Framework\App\Action\Context; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; - -/** - * Class MassHoldTest - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class MassHoldTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Sales\Controller\Adminhtml\Order\MassHold - */ - protected $massAction; - - /** - * @var Context|\PHPUnit_Framework_MockObject_MockObject - */ - protected $contextMock; - - /** - * @var \Magento\Backend\Model\View\Result\Redirect|\PHPUnit_Framework_MockObject_MockObject - */ - protected $resultRedirectMock; - - /** - * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject - */ - protected $requestMock; - - /** - * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $responseMock; - - /** - * @var \Magento\Framework\Message\Manager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $messageManagerMock; - - /** - * @var \Magento\Framework\ObjectManager\ObjectManager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $objectManagerMock; - - /** - * @var \Magento\Backend\Model\Session|\PHPUnit_Framework_MockObject_MockObject - */ - protected $sessionMock; - - /** - * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject - */ - protected $actionFlagMock; - - /** - * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject - */ - protected $helperMock; - - /** - * @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderMock; - - /** - * @var \Magento\Sales\Model\ResourceModel\Order\Collection|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderCollectionMock; - - /** - * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderCollectionFactoryMock; - - /** - * @var \Magento\Ui\Component\MassAction\Filter|\PHPUnit_Framework_MockObject_MockObject - */ - protected $filterMock; - - /** - * @var \Magento\Sales\Api\OrderManagementInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderManagementMock; - - /** - * Test setup - */ - protected function setUp() - { - $objectManagerHelper = new ObjectManagerHelper($this); - $this->orderManagementMock = $this->getMockBuilder(\Magento\Sales\Api\OrderManagementInterface::class) - ->getMockForAbstractClass(); - $this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $resultRedirectFactory = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); - $this->responseMock = $this->createMock(\Magento\Framework\App\ResponseInterface::class); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) - ->disableOriginalConstructor()->getMock(); - $this->objectManagerMock = $this->createPartialMock( - \Magento\Framework\ObjectManager\ObjectManager::class, - ['create'] - ); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); - $this->orderCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - $orderCollection = \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class; - $this->orderCollectionFactoryMock = $this->getMockBuilder($orderCollection) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $redirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $resultFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $resultFactoryMock->expects($this->any()) - ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($redirectMock); - - $this->sessionMock = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); - $this->actionFlagMock = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get', 'set']); - $this->helperMock = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); - $this->resultRedirectMock = $this->createMock(\Magento\Backend\Model\View\Result\Redirect::class); - $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirectMock); - - $this->contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); - $this->contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock); - $this->contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock); - $this->contextMock - ->expects($this->once()) - ->method('getResultRedirectFactory') - ->willReturn($resultRedirectFactory); - $this->contextMock->expects($this->any()) - ->method('getResultFactory') - ->willReturn($resultFactoryMock); - - $this->filterMock = $this->createMock(\Magento\Ui\Component\MassAction\Filter::class); - $this->filterMock->expects($this->once()) - ->method('getCollection') - ->with($this->orderCollectionMock) - ->willReturn($this->orderCollectionMock); - $this->orderCollectionFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->orderCollectionMock); - - $this->massAction = $objectManagerHelper->getObject( - \Magento\Sales\Controller\Adminhtml\Order\MassHold::class, - [ - 'context' => $this->contextMock, - 'filter' => $this->filterMock, - 'collectionFactory' => $this->orderCollectionFactoryMock, - 'orderManagement' => $this->orderManagementMock - ] - ); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testExecuteOneOrderPutOnHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canHold') - ->willReturn(true); - $this->orderManagementMock->expects($this->once()) - ->method('hold'); - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $order2->expects($this->once()) - ->method('canHold') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('1 order(s) were not put on hold.'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccessMessage') - ->with('You have put 1 order(s) on hold.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testExecuteNoOrdersPutOnHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canHold') - ->willReturn(false); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $order2->expects($this->once()) - ->method('canHold') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('No order(s) were put on hold.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } -} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php deleted file mode 100644 index 56473ec948f27..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php +++ /dev/null @@ -1,261 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Sales\Test\Unit\Controller\Adminhtml\Order; - -use Magento\Framework\App\Action\Context; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; - -/** - * Class MassHoldTest - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class MassUnholdTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Sales\Controller\Adminhtml\Order\MassUnhold - */ - protected $massAction; - - /** - * @var Context|\PHPUnit_Framework_MockObject_MockObject - */ - protected $contextMock; - - /** - * @var \Magento\Backend\Model\View\Result\Redirect|\PHPUnit_Framework_MockObject_MockObject - */ - protected $resultRedirectMock; - - /** - * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject - */ - protected $requestMock; - - /** - * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $responseMock; - - /** - * @var \Magento\Framework\Message\Manager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $messageManagerMock; - - /** - * @var \Magento\Framework\ObjectManager\ObjectManager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $objectManagerMock; - - /** - * @var \Magento\Backend\Model\Session|\PHPUnit_Framework_MockObject_MockObject - */ - protected $sessionMock; - - /** - * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject - */ - protected $actionFlagMock; - - /** - * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject - */ - protected $helperMock; - - /** - * @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderMock; - - /** - * @var \Magento\Sales\Model\ResourceModel\Order\Collection|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderCollectionMock; - - /** - * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $orderCollectionFactoryMock; - - /** - * @var \Magento\Ui\Component\MassAction\Filter|\PHPUnit_Framework_MockObject_MockObject - */ - protected $filterMock; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $orderManagementMock; - - /** - * Test setup - */ - protected function setUp() - { - $objectManagerHelper = new ObjectManagerHelper($this); - $this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $resultRedirectFactory = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); - $this->responseMock = $this->createMock(\Magento\Framework\App\ResponseInterface::class); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) - ->disableOriginalConstructor()->getMock(); - $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManager\ObjectManager::class); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); - - $this->orderCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - $orderCollection = \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class; - $this->orderCollectionFactoryMock = $this->getMockBuilder($orderCollection) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->sessionMock = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); - $this->actionFlagMock = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get', 'set']); - $this->helperMock = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); - $this->resultRedirectMock = $this->createMock(\Magento\Backend\Model\View\Result\Redirect::class); - $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirectMock); - - $redirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $resultFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $resultFactoryMock->expects($this->any()) - ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($redirectMock); - - $this->contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); - $this->contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock); - $this->contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock); - $this->contextMock - ->expects($this->once()) - ->method('getResultRedirectFactory') - ->willReturn($resultRedirectFactory); - $this->contextMock->expects($this->any()) - ->method('getResultFactory') - ->willReturn($resultFactoryMock); - - $this->filterMock = $this->createMock(\Magento\Ui\Component\MassAction\Filter::class); - $this->filterMock->expects($this->once()) - ->method('getCollection') - ->with($this->orderCollectionMock) - ->willReturn($this->orderCollectionMock); - $this->orderCollectionFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->orderCollectionMock); - - $this->orderManagementMock = $this->createMock(\Magento\Sales\Api\OrderManagementInterface::class); - - $this->massAction = $objectManagerHelper->getObject( - \Magento\Sales\Controller\Adminhtml\Order\MassUnhold::class, - [ - 'context' => $this->contextMock, - 'filter' => $this->filterMock, - 'collectionFactory' => $this->orderCollectionFactoryMock, - 'orderManagement' => $this->orderManagementMock - ] - ); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testExecuteOneOrdersReleasedFromHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canUnhold') - ->willReturn(true); - $order1->expects($this->once()) - ->method('getEntityId'); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn(count($orders)); - - $order2->expects($this->once()) - ->method('canUnhold') - ->willReturn(false); - - $this->orderManagementMock->expects($this->atLeastOnce())->method('unHold')->willReturn(true); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('1 order(s) were not released from on hold status.'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccessMessage') - ->with('1 order(s) have been released from on hold status.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testExecuteNoReleasedOrderFromHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canUnhold') - ->willReturn(false); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn(count($orders)); - - $order2->expects($this->once()) - ->method('canUnhold') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addErrorMessage') - ->with('No order(s) were released from on hold status.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } -} From c20f29f64d188c84edc157a64c772e29ea7d357c Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Tue, 18 Sep 2018 11:51:55 -0500 Subject: [PATCH 047/118] MAGETWO-87454: Catalog Products List widget doesn't work with 'contains/not contains' operator --- .../Rule/Model/Condition/Sql/Builder.php | 38 +++++++++++++----- .../Block/Product/ProductListTest.php | 39 +++++++++++++++++++ 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index 0b824ca94ca3e..995999c3a0cde 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -41,6 +41,14 @@ class Builder '!()' => ':field NOT IN (?)', ]; + /** + * @var array + */ + private $stringConditionOperatorMap = [ + '{}' => ':field LIKE ?', + '!{}' => ':field NOT LIKE ?', + ]; + /** * @var \Magento\Rule\Model\Condition\Sql\ExpressionFactory */ @@ -152,15 +160,27 @@ protected function _getMappedSqlCondition( } $defaultValue = 0; - $sql = str_replace( - ':field', - $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue), - $this->_conditionOperatorMap[$conditionOperator] - ); - - $bindValue = $condition->getBindArgumentValue(); - $expression = $value . $this->_connection->quoteInto($sql, $bindValue); - + //operator 'contains {}' is mapped to 'IN()' query that cannot work with substrings + // adding mapping to 'LIKE %%' + if ($condition->getInputType() === 'string' + && in_array($conditionOperator, array_keys($this->stringConditionOperatorMap), true) + ) { + $sql = str_replace( + ':field', + $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue), + $this->stringConditionOperatorMap[$conditionOperator] + ); + $bindValue = $condition->getBindArgumentValue(); + $expression = $value . $this->_connection->quoteInto($sql, "%$bindValue%"); + } else { + $sql = str_replace( + ':field', + $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue), + $this->_conditionOperatorMap[$conditionOperator] + ); + $bindValue = $condition->getBindArgumentValue(); + $expression = $value . $this->_connection->quoteInto($sql, $bindValue); + } // values for multiselect attributes can be saved in comma-separated format // below is a solution for matching such conditions with selected values if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) { diff --git a/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php b/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php index ba428dd00ddb4..2f2029d2f13e1 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php @@ -131,4 +131,43 @@ private function performAssertions(int $count) "Product collection was not filtered according to the widget condition." ); } + + /** + * Check that collection returns correct result if use not contains operator for string attribute + * + * @magentoDbIsolation disabled + * @magentoDataFixture Magento/Catalog/_files/product_special_price.php + * @magentoDataFixture Magento/Catalog/_files/product_virtual.php + * @dataProvider createCollectionForSkuDataProvider + * @return void + */ + public function testCreateCollectionForSku($encodedConditions) + { + $this->block->setData('conditions_encoded', $encodedConditions); + $productCollection = $this->block->createCollection(); + $productCollection->load(); + $this->assertEquals( + 1, + $productCollection->count(), + "Product collection was not filtered according to the widget condition." + ); + $this->assertEquals('virtual-product', $productCollection->getFirstItem()->getSku()); + } + + /** + * @return array + */ + public function createCollectionForSkuDataProvider() + { + return [ + 'contains' => ['^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,' + . '`aggregator`:`all`,`value`:`1`,`new_child`:``^],' + . '`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,' + . '`attribute`:`sku`,`operator`:`^[^]`,`value`:`virtual`^]^]'], + 'not contains' => ['^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,' + . '`aggregator`:`all`,`value`:`1`,`new_child`:``^],' + . '`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,' + . '`attribute`:`sku`,`operator`:`!^[^]`,`value`:`simple`^]^]'] + ]; + } } From eff16a418d41b7cda59c37065b8829ab5b6ce0f5 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Thu, 20 Sep 2018 16:51:44 -0500 Subject: [PATCH 048/118] MAGETWO-92898: Bundle Product enable/disable refresh issue on products page. - Unskip Bundle test that no longer encounters bug with enable/disable flow --- .../Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml index 0fb8a7b88250c..5b2b771434b73 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml @@ -17,9 +17,6 @@ <severity value="CRITICAL"/> <testCaseId value="MC-217"/> <group value="Bundle"/> - <skip> - <issueId value="MAGETWO-92898"/> - </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> From c8f3f1751656d930517188edf7c2117e951046d9 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Thu, 20 Sep 2018 16:53:25 -0500 Subject: [PATCH 049/118] MAGETWO-94819: Swatch validation breaks the whole attribute form --- .../Controller/Adminhtml/Product/Attribute/Save.php | 12 ++++++------ .../Adminhtml/Product/Attribute/Validate.php | 10 +++++----- .../Adminhtml/Product/Attribute/SaveTest.php | 12 ++++++------ .../Adminhtml/Product/Attribute/ValidateTest.php | 12 ++++++------ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 435fdb0b41301..985d812fc742b 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -82,7 +82,7 @@ class Save extends Attribute implements HttpPostActionInterface /** * @var FormData|null */ - private $dataSerializer; + private $formDataSerializer; /** * @param Context $context @@ -97,7 +97,7 @@ class Save extends Attribute implements HttpPostActionInterface * @param Product $productHelper * @param LayoutFactory $layoutFactory * @param Presentation|null $presentation - * @param FormData|null $dataSerializer + * @param FormData|null $formDataSerializer * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -113,7 +113,7 @@ public function __construct( Product $productHelper, LayoutFactory $layoutFactory, Presentation $presentation = null, - FormData $dataSerializer = null + FormData $formDataSerializer = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->buildFactory = $buildFactory; @@ -124,7 +124,7 @@ public function __construct( $this->groupCollectionFactory = $groupCollectionFactory; $this->layoutFactory = $layoutFactory; $this->presentation = $presentation ?: ObjectManager::getInstance()->get(Presentation::class); - $this->dataSerializer = $dataSerializer + $this->formDataSerializer = $formDataSerializer ?: ObjectManager::getInstance()->get(FormData::class); } @@ -140,7 +140,7 @@ public function __construct( public function execute() { try { - $optionData = $this->dataSerializer + $optionData = $this->formDataSerializer ->unserialize($this->getRequest()->getParam('serialized_options', '[]')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be saved due to an error. Verify your information and try again. " @@ -150,7 +150,7 @@ public function execute() } $data = $this->getRequest()->getPostValue(); - $data = array_merge_recursive( + $data = array_replace_recursive( $data, $optionData ); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index 4e33fc737f0c4..8a9d0c9b612cb 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -41,7 +41,7 @@ class Validate extends AttributeAction implements HttpGetActionInterface, HttpPo /** * @var FormData|null */ - private $dataSerializer; + private $formDataSerializer; /** * Constructor @@ -53,7 +53,7 @@ class Validate extends AttributeAction implements HttpGetActionInterface, HttpPo * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\View\LayoutFactory $layoutFactory * @param array $multipleAttributeList - * @param FormData|null $dataSerializer + * @param FormData|null $formDataSerializer */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -63,13 +63,13 @@ public function __construct( \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, \Magento\Framework\View\LayoutFactory $layoutFactory, array $multipleAttributeList = [], - FormData $dataSerializer = null + FormData $formDataSerializer = null ) { parent::__construct($context, $attributeLabelCache, $coreRegistry, $resultPageFactory); $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; $this->multipleAttributeList = $multipleAttributeList; - $this->dataSerializer = $dataSerializer ?: ObjectManager::getInstance() + $this->formDataSerializer = $formDataSerializer ?: ObjectManager::getInstance() ->get(FormData::class); } @@ -85,7 +85,7 @@ public function execute() $response = new DataObject(); $response->setError(false); try { - $optionsData = $this->dataSerializer + $optionsData = $this->formDataSerializer ->unserialize($this->getRequest()->getParam('serialized_options', '[]')); } catch (\InvalidArgumentException $e) { $message = __("The attribute couldn't be validated due to an error. Verify your information and try again. " diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php index e73f3527517f8..ced65b2d2e15d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php @@ -87,7 +87,7 @@ class SaveTest extends AttributeTest /** * @var FormData|\PHPUnit_Framework_MockObject_MockObject */ - private $dataSerializerMock; + private $formDataSerializerMock; /** * @var ProductAttributeInterface|\PHPUnit_Framework_MockObject_MockObject @@ -135,7 +135,7 @@ protected function setUp() $this->inputTypeValidatorMock = $this->getMockBuilder(InputTypeValidator::class) ->disableOriginalConstructor() ->getMock(); - $this->dataSerializerMock = $this->getMockBuilder(FormData::class) + $this->formDataSerializerMock = $this->getMockBuilder(FormData::class) ->disableOriginalConstructor() ->getMock(); $this->productAttributeMock = $this->getMockBuilder(ProductAttributeInterface::class) @@ -170,7 +170,7 @@ protected function getModel() 'validatorFactory' => $this->validatorFactoryMock, 'groupCollectionFactory' => $this->groupCollectionFactoryMock, 'layoutFactory' => $this->layoutFactoryMock, - 'dataSerializer' => $this->dataSerializerMock, + 'formDataSerializer' => $this->formDataSerializerMock, ]); } @@ -182,7 +182,7 @@ public function testExecuteWithEmptyData() ['isAjax', null, null], ['serialized_options', '[]', ''], ]); - $this->dataSerializerMock + $this->formDataSerializerMock ->expects($this->once()) ->method('unserialize') ->with('') @@ -213,7 +213,7 @@ public function testExecute() ['isAjax', null, null], ['serialized_options', '[]', ''], ]); - $this->dataSerializerMock + $this->formDataSerializerMock ->expects($this->once()) ->method('unserialize') ->with('') @@ -273,7 +273,7 @@ public function testExecuteWithOptionsDataError() ['isAjax', null, true], ['serialized_options', '[]', $serializedOptions], ]); - $this->dataSerializerMock + $this->formDataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php index 666e6c1942c7a..c6210f93e1290 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/ValidateTest.php @@ -65,7 +65,7 @@ class ValidateTest extends AttributeTest /** * @var FormData|\PHPUnit_Framework_MockObject_MockObject */ - private $dataSerializerMock; + private $formDataSerializerMock; protected function setUp() { @@ -92,7 +92,7 @@ protected function setUp() ->getMock(); $this->layoutMock = $this->getMockBuilder(LayoutInterface::class) ->getMockForAbstractClass(); - $this->dataSerializerMock = $this->getMockBuilder(FormData::class) + $this->formDataSerializerMock = $this->getMockBuilder(FormData::class) ->disableOriginalConstructor() ->getMock(); @@ -116,7 +116,7 @@ protected function getModel() 'resultJsonFactory' => $this->resultJsonFactoryMock, 'layoutFactory' => $this->layoutFactoryMock, 'multipleAttributeList' => ['select' => 'option'], - 'dataSerializer' => $this->dataSerializerMock, + 'formDataSerializer' => $this->formDataSerializerMock, ] ); } @@ -184,7 +184,7 @@ public function testUniqueValidation(array $options, $isError) ['serialized_options', '[]', $serializedOptions], ]); - $this->dataSerializerMock + $this->formDataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) @@ -319,7 +319,7 @@ public function testEmptyOption(array $options, $result) ['serialized_options', '[]', $serializedOptions], ]); - $this->dataSerializerMock + $this->formDataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) @@ -431,7 +431,7 @@ public function testExecuteWithOptionsDataError() ['serialized_options', '[]', $serializedOptions], ]); - $this->dataSerializerMock + $this->formDataSerializerMock ->expects($this->once()) ->method('unserialize') ->with($serializedOptions) From 60f33baab9a476c4320f17b80e1e1df74543ac9f Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 21 Sep 2018 14:54:58 +0300 Subject: [PATCH 050/118] MAGETWO-92195: Wrong order request flow --- .../Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php index bd377e40f1849..e862710379a04 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php @@ -13,7 +13,7 @@ use Magento\Sales\Api\OrderManagementInterface; /** - * Class MassUnhold + * Class MassUnhold, change status for select orders * * @package Magento\Sales\Controller\Adminhtml\Order */ From cdc0fd39bac4218fe16eecb34ee7ffa407ac94ca Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 21 Sep 2018 15:58:18 +0300 Subject: [PATCH 051/118] MAGETWO-70943: Incorrect reset password flow --- .../Api/AccountManagementInterface.php | 11 ++- .../Controller/Account/CreatePassword.php | 21 +++-- .../Controller/Account/ResetPasswordPost.php | 39 +++++---- .../Customer/Model/AccountManagement.php | 83 +++++++++++++++++-- .../email/password_reset_confirmation.html | 3 +- .../form/resetforgottenpassword.phtml | 2 +- .../Customer/Controller/AccountTest.php | 12 +-- .../Customer/Model/AccountManagementTest.php | 58 ++++++++++++- .../Magento/Framework/Math/Random.php | 68 +++++---------- 9 files changed, 202 insertions(+), 95 deletions(-) diff --git a/app/code/Magento/Customer/Api/AccountManagementInterface.php b/app/code/Magento/Customer/Api/AccountManagementInterface.php index d2f9fb7ebc420..10fc2349968ea 100644 --- a/app/code/Magento/Customer/Api/AccountManagementInterface.php +++ b/app/code/Magento/Customer/Api/AccountManagementInterface.php @@ -7,6 +7,8 @@ namespace Magento\Customer\Api; +use Magento\Framework\Exception\InputException; + /** * Interface for managing customers accounts. * @api @@ -144,19 +146,24 @@ public function initiatePasswordReset($email, $template, $websiteId = null); /** * Reset customer password. * - * @param string $email + * @param string $email If empty value given then the customer + * will be matched by the RP token. * @param string $resetToken * @param string $newPassword + * * @return bool true on success * @throws \Magento\Framework\Exception\LocalizedException + * @throws InputException */ public function resetPassword($email, $resetToken, $newPassword); /** * Check if password reset token is valid. * - * @param int $customerId + * @param int $customerId If null is given then a customer + * will be matched by the RP token. * @param string $resetPasswordLinkToken + * * @return bool True if the token is valid * @throws \Magento\Framework\Exception\State\InputMismatchException If token is mismatched * @throws \Magento\Framework\Exception\State\ExpiredException If token is expired diff --git a/app/code/Magento/Customer/Controller/Account/CreatePassword.php b/app/code/Magento/Customer/Controller/Account/CreatePassword.php index fb2e3dd42908b..124ac912a7ccf 100644 --- a/app/code/Magento/Customer/Controller/Account/CreatePassword.php +++ b/app/code/Magento/Customer/Controller/Account/CreatePassword.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -8,10 +7,16 @@ use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Model\Session; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\View\Result\PageFactory; use Magento\Framework\App\Action\Context; -class CreatePassword extends \Magento\Customer\Controller\AbstractAccount +/** + * Class CreatePassword + * + * @package Magento\Customer\Controller\Account + */ +class CreatePassword extends \Magento\Customer\Controller\AbstractAccount implements HttpGetActionInterface { /** * @var \Magento\Customer\Api\AccountManagementInterface @@ -54,27 +59,27 @@ public function __construct( public function execute() { $resetPasswordToken = (string)$this->getRequest()->getParam('token'); - $customerId = (int)$this->getRequest()->getParam('id'); - $isDirectLink = $resetPasswordToken != '' && $customerId != 0; + $isDirectLink = $resetPasswordToken != ''; if (!$isDirectLink) { $resetPasswordToken = (string)$this->session->getRpToken(); - $customerId = (int)$this->session->getRpCustomerId(); } try { - $this->accountManagement->validateResetPasswordLinkToken($customerId, $resetPasswordToken); + $this->accountManagement->validateResetPasswordLinkToken(null, $resetPasswordToken); if ($isDirectLink) { $this->session->setRpToken($resetPasswordToken); - $this->session->setRpCustomerId($customerId); $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('*/*/createpassword'); + return $resultRedirect; } else { /** @var \Magento\Framework\View\Result\Page $resultPage */ $resultPage = $this->resultPageFactory->create(); - $resultPage->getLayout()->getBlock('resetPassword')->setCustomerId($customerId) + $resultPage->getLayout() + ->getBlock('resetPassword') ->setResetPasswordLinkToken($resetPasswordToken); + return $resultPage; } } catch (\Exception $exception) { diff --git a/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php b/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php index 3de44e35d2447..27a00f86dd95d 100644 --- a/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php +++ b/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php @@ -1,6 +1,5 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,11 +9,16 @@ use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Model\Session; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Exception\InputException; use Magento\Customer\Model\Customer\CredentialsValidator; -use Magento\Framework\App\ObjectManager; -class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount +/** + * Class ResetPasswordPost + * + * @package Magento\Customer\Controller\Account + */ +class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount implements HttpPostActionInterface { /** * @var \Magento\Customer\Api\AccountManagementInterface @@ -31,17 +35,14 @@ class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount */ protected $session; - /** - * @var CredentialsValidator - */ - private $credentialsValidator; - /** * @param Context $context * @param Session $customerSession * @param AccountManagementInterface $accountManagement * @param CustomerRepositoryInterface $customerRepository * @param CredentialsValidator|null $credentialsValidator + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( Context $context, @@ -53,8 +54,6 @@ public function __construct( $this->session = $customerSession; $this->accountManagement = $accountManagement; $this->customerRepository = $customerRepository; - $this->credentialsValidator = $credentialsValidator ?: ObjectManager::getInstance() - ->get(CredentialsValidator::class); parent::__construct($context); } @@ -70,29 +69,32 @@ public function execute() /** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); $resetPasswordToken = (string)$this->getRequest()->getQuery('token'); - $customerId = (int)$this->getRequest()->getQuery('id'); $password = (string)$this->getRequest()->getPost('password'); $passwordConfirmation = (string)$this->getRequest()->getPost('password_confirmation'); if ($password !== $passwordConfirmation) { $this->messageManager->addError(__("New Password and Confirm New Password values didn't match.")); - $resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]); + $resultRedirect->setPath('*/*/createPassword', ['token' => $resetPasswordToken]); + return $resultRedirect; } if (iconv_strlen($password) <= 0) { $this->messageManager->addError(__('Please enter a new password.')); - $resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]); + $resultRedirect->setPath('*/*/createPassword', ['token' => $resetPasswordToken]); + return $resultRedirect; } try { - $customerEmail = $this->customerRepository->getById($customerId)->getEmail(); - $this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $password); - $this->accountManagement->resetPassword($customerEmail, $resetPasswordToken, $password); + $this->accountManagement->resetPassword( + null, + $resetPasswordToken, + $password + ); $this->session->unsRpToken(); - $this->session->unsRpCustomerId(); $this->messageManager->addSuccess(__('You updated your password.')); $resultRedirect->setPath('*/*/login'); + return $resultRedirect; } catch (InputException $e) { $this->messageManager->addError($e->getMessage()); @@ -102,7 +104,8 @@ public function execute() } catch (\Exception $exception) { $this->messageManager->addError(__('Something went wrong while saving the new password.')); } - $resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]); + $resultRedirect->setPath('*/*/createPassword', ['token' => $resetPasswordToken]); + return $resultRedirect; } } diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index fe17adcb09c0d..52264c78b7717 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -20,6 +20,7 @@ use Magento\Customer\Model\Metadata\Validator; use Magento\Eav\Model\Validator\Attribute\Backend; use Magento\Framework\Api\ExtensibleDataObjectConverter; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\App\Area; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\ObjectManager; @@ -41,6 +42,7 @@ use Magento\Framework\Intl\DateTimeFactory; use Magento\Framework\Mail\Template\TransportBuilder; use Magento\Framework\Math\Random; +use Magento\Framework\Phrase; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Registry; use Magento\Framework\Stdlib\DateTime; @@ -326,6 +328,11 @@ class AccountManagement implements AccountManagementInterface */ private $accountConfirmation; + /** + * @var SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + /** * @param CustomerFactory $customerFactory * @param ManagerInterface $eventManager @@ -356,6 +363,7 @@ class AccountManagement implements AccountManagementInterface * @param SessionManagerInterface|null $sessionManager * @param SaveHandlerInterface|null $saveHandler * @param CollectionFactory|null $visitorCollectionFactory + * @param SearchCriteriaBuilder|null $searchCriteriaBuilder * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -387,7 +395,8 @@ public function __construct( AccountConfirmation $accountConfirmation = null, SessionManagerInterface $sessionManager = null, SaveHandlerInterface $saveHandler = null, - CollectionFactory $visitorCollectionFactory = null + CollectionFactory $visitorCollectionFactory = null, + SearchCriteriaBuilder $searchCriteriaBuilder = null ) { $this->customerFactory = $customerFactory; $this->eventManager = $eventManager; @@ -423,6 +432,8 @@ public function __construct( ?: ObjectManager::getInstance()->get(SaveHandlerInterface::class); $this->visitorCollectionFactory = $visitorCollectionFactory ?: ObjectManager::getInstance()->get(CollectionFactory::class); + $this->searchCriteriaBuilder = $searchCriteriaBuilder + ?: ObjectManager::getInstance()->get(SearchCriteriaBuilder::class); } /** @@ -591,6 +602,43 @@ public function initiatePasswordReset($email, $template, $websiteId = null) return false; } + /** + * Match a customer by their RP token. + * + * @param string $rpToken + * @throws ExpiredException + * @throws NoSuchEntityException + * + * @return CustomerInterface + * @throws LocalizedException + */ + private function matchCustomerByRpToken(string $rpToken): CustomerInterface + { + $this->searchCriteriaBuilder->addFilter( + 'rp_token', + $rpToken + ); + $this->searchCriteriaBuilder->setPageSize(1); + $found = $this->customerRepository->getList( + $this->searchCriteriaBuilder->create() + ); + if ($found->getTotalCount() > 1) { + //Failed to generated unique RP token + throw new ExpiredException( + new Phrase('Reset password token expired.') + ); + } + if ($found->getTotalCount() === 0) { + //Customer with such token not found. + throw NoSuchEntityException::singleField( + 'rp_token', + $rpToken + ); + } + //Unique customer found. + return $found->getItems()[0]; + } + /** * Handle not supported template * @@ -613,18 +661,26 @@ private function handleUnknownTemplate($template) /** * @inheritdoc */ - public function resetPassword($email, $resetToken, $newPassword) + public function resetPassword(?string $email, string $resetToken, string $newPassword): bool { - $customer = $this->customerRepository->get($email); + if (!$email) { + $customer = $this->matchCustomerByRpToken($resetToken); + $email = $customer->getEmail(); + } else { + $customer = $this->customerRepository->get($email); + } //Validate Token and new password strength $this->validateResetPasswordToken($customer->getId(), $resetToken); + $this->credentialsValidator->checkPasswordDifferentFromEmail( + $email, + $newPassword + ); $this->checkPasswordStrength($newPassword); //Update secure data $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId()); $customerSecure->setRpToken(null); $customerSecure->setRpTokenCreatedAt(null); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); - $this->getAuthentication()->unlock($customer->getId()); $this->sessionManager->destroy(); $this->destroyCustomerSessions($customer->getId()); $this->customerRepository->save($customer); @@ -955,6 +1011,8 @@ protected function createPasswordHash($password) } /** + * Returns eval validator + * * @return Backend */ private function getEavValidator() @@ -1033,10 +1091,11 @@ public function isCustomerInStore($customerWebsiteId, $storeId) * @throws \Magento\Framework\Exception\State\ExpiredException If token is expired * @throws \Magento\Framework\Exception\InputException If token or customer id is invalid * @throws \Magento\Framework\Exception\NoSuchEntityException If customer doesn't exist + * @throws LocalizedException */ - private function validateResetPasswordToken($customerId, $resetPasswordLinkToken) + private function validateResetPasswordToken(?int $customerId, ?string $resetPasswordLinkToken) : bool { - if (empty($customerId) || $customerId < 0) { + if ($customerId !== null && $customerId <= 0) { throw new InputException( __( 'Invalid value of "%value" provided for the %fieldName field.', @@ -1044,21 +1103,24 @@ private function validateResetPasswordToken($customerId, $resetPasswordLinkToken ) ); } + + if ($customerId === null) { + //Looking for the customer. + $customerId = $this->matchCustomerByRpToken($resetPasswordLinkToken) + ->getId(); + } if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) { $params = ['fieldName' => 'resetPasswordLinkToken']; throw new InputException(__('"%fieldName" is required. Enter and try again.', $params)); } - $customerSecureData = $this->customerRegistry->retrieveSecureData($customerId); $rpToken = $customerSecureData->getRpToken(); $rpTokenCreatedAt = $customerSecureData->getRpTokenCreatedAt(); - if (!Security::compareStrings($rpToken, $resetPasswordLinkToken)) { throw new InputMismatchException(__('The password token is mismatched. Reset and try again.')); } elseif ($this->isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)) { throw new ExpiredException(__('The password token is expired. Reset and try again.')); } - return true; } @@ -1141,6 +1203,7 @@ protected function sendPasswordResetNotificationEmail($customer) * @param int|string|null $defaultStoreId * @return int * @deprecated 100.1.0 + * @throws LocalizedException */ protected function getWebsiteStoreId($customer, $defaultStoreId = null) { @@ -1153,6 +1216,8 @@ protected function getWebsiteStoreId($customer, $defaultStoreId = null) } /** + * Return array with template types + * * @return array * @deprecated 100.1.0 */ diff --git a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html index 6c17762a88227..f33350ea48241 100644 --- a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html +++ b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html @@ -21,7 +21,8 @@ <table class="inner-wrapper" border="0" cellspacing="0" cellpadding="0" align="center"> <tr> <td align="center"> - <a href="{{var this.getUrl($store,'customer/account/createPassword/',[_query:[id:$customer.id,token:$customer.rp_token],_nosid:1])}}" target="_blank">{{trans "Set a New Password"}}</a> + <a href="{{var this.getUrl($store,'customer/account/createPassword/',[_query:[token:$customer.rp_token],_nosid:1])}}" target="_blank">{{trans "Set a New Password"}}</a> + </td> </tr> </table> diff --git a/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml b/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml index 15e570da04beb..e79cea80ac838 100644 --- a/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml @@ -8,7 +8,7 @@ /** @var \Magento\Customer\Block\Account\Resetpassword $block */ ?> -<form action="<?= $block->escapeUrl($block->getUrl('*/*/resetpasswordpost', ['_query' => ['id' => $block->getCustomerId(), 'token' => $block->getResetPasswordLinkToken()]])) ?>" +<form action="<?= $block->escapeUrl($block->getUrl('*/*/resetpasswordpost', ['_query' => ['token' => $block->getResetPasswordLinkToken()]])) ?>" method="post" <?php if ($block->isAutocompleteDisabled()) :?> autocomplete="off"<?php endif; ?> id="form-validate" diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index 921fa81fa6f23..12855e457effd 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -130,7 +130,6 @@ public function testCreatepasswordActionWithDirectLink() $customer->save(); $this->getRequest()->setParam('token', $token); - $this->getRequest()->setParam('id', $customer->getId()); $this->dispatch('customer/account/createPassword'); @@ -138,12 +137,13 @@ public function testCreatepasswordActionWithDirectLink() $this->assertEquals(302, $response->getHttpResponseCode()); $text = $response->getBody(); $this->assertFalse((bool)preg_match('/' . $token . '/m', $text)); - $this->assertRedirect($this->stringContains('customer/account/createpassword')); + $this->assertRedirect( + $this->stringContains('customer/account/createpassword') + ); - /** @var \Magento\Customer\Model\Session $customer */ - $session = Bootstrap::getObjectManager()->get(\Magento\Customer\Model\Session::class); + /** @var Session $customer */ + $session = Bootstrap::getObjectManager()->get(Session::class); $this->assertEquals($token, $session->getRpToken()); - $this->assertEquals($customer->getId(), $session->getRpCustomerId()); $this->assertNotContains($token, $response->getHeader('Location')->getFieldValue()); } @@ -419,6 +419,7 @@ public function testResetPasswordPostNoTokenAction() $this->getRequest() ->setParam('id', 1) ->setParam('token', '8ed8677e6c79e68b94e61658bd756ea5') + ->setMethod('POST') ->setPostValue([ 'password' => 'new-password', 'password_confirmation' => 'new-password', @@ -441,6 +442,7 @@ public function testResetPasswordPostAction() $this->getRequest() ->setQueryValue('id', 1) ->setQueryValue('token', '8ed8677e6c79e68b94e61658bd756ea5') + ->setMethod('POST') ->setPostValue([ 'password' => 'new-Password1', 'password_confirmation' => 'new-Password1', diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php index f5b6fdc93d32f..4810b6c28caef 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php @@ -357,6 +357,29 @@ public function testValidateResetPasswordLinkTokenNull() } } + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testValidateResetPasswordLinkTokenWithoutId() + { + $token = 'randomStr123'; + $this->setResetPasswordData($token, 'Y-m-d H:i:s'); + $this->assertTrue( + $this->accountManagement->validateResetPasswordLinkToken(null, $token) + ); + } + /** + * @magentoDataFixture Magento/Customer/_files/two_customers.php + * @expectedException \Magento\Framework\Exception\State\ExpiredException + */ + public function testValidateResetPasswordLinkTokenAmbiguous() + { + $token = 'randomStr123'; + $this->setResetPasswordData($token, 'Y-m-d H:i:s', 1); + $this->setResetPasswordData($token, 'Y-m-d H:i:s', 2); + $this->accountManagement->validateResetPasswordLinkToken(null, $token); + } + /** * @magentoAppArea frontend * @magentoDataFixture Magento/Customer/_files/customer.php @@ -512,6 +535,31 @@ public function testResetPasswordTokenInvalidUserEmail() } } + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testResetPasswordWithoutEmail() + { + $resetToken = 'lsdj579slkj5987slkj595lkj'; + $password = 'new_Password123'; + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s'); + $this->assertTrue( + $this->accountManagement->resetPassword(null, $resetToken, $password) + ); + } + /** + * @magentoDataFixture Magento/Customer/_files/two_customers.php + * @expectedException \Magento\Framework\Exception\State\ExpiredException + */ + public function testResetPasswordAmbiguousToken() + { + $resetToken = 'lsdj579slkj5987slkj595lkj'; + $password = 'new_Password123'; + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s', 1); + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s', 2); + $this->accountManagement->resetPassword(null, $resetToken, $password); + } + /** * @magentoAppArea frontend * @magentoAppIsolation enabled @@ -960,10 +1008,14 @@ public function testGetDefaultAddressesForNonExistentAddress() * * @param $resetToken * @param $date + * @param int $customerIdFromFixture Which customer to use. + * @throws \Exception */ - protected function setResetPasswordData($resetToken, $date) - { - $customerIdFromFixture = 1; + protected function setResetPasswordData( + $resetToken, + $date, + int $customerIdFromFixture = 1 + ) { /** @var \Magento\Customer\Model\Customer $customerModel */ $customerModel = $this->objectManager->create(\Magento\Customer\Model\Customer::class); $customerModel->load($customerIdFromFixture); diff --git a/lib/internal/Magento/Framework/Math/Random.php b/lib/internal/Magento/Framework/Math/Random.php index 7cb70c9a822cc..c2059e1935a80 100644 --- a/lib/internal/Magento/Framework/Math/Random.php +++ b/lib/internal/Magento/Framework/Math/Random.php @@ -5,6 +5,9 @@ */ namespace Magento\Framework\Math; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; + /** * Random data generator * @@ -24,41 +27,24 @@ class Random /**#@-*/ /** - * Get random string + * Get random string. * * @param int $length * @param null|string $chars + * * @return string - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function getRandomString($length, $chars = null) { $str = ''; if (null === $chars) { - $chars = self::CHARS_LOWERS . self::CHARS_UPPERS . self::CHARS_DIGITS; + $chars = self::CHARS_LOWERS.self::CHARS_UPPERS.self::CHARS_DIGITS; } - if (function_exists('openssl_random_pseudo_bytes')) { - // use openssl lib if it is installed - for ($i = 0, $lc = strlen($chars) - 1; $i < $length; $i++) { - $bytes = openssl_random_pseudo_bytes(PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $rand = abs(hexdec($hex) % $lc); // random integer from 0 to $lc - $str .= $chars[$rand]; // random character in $chars - } - } elseif ($fp = @fopen('/dev/urandom', 'rb')) { - // attempt to use /dev/urandom if it exists but openssl isn't available - for ($i = 0, $lc = strlen($chars) - 1; $i < $length; $i++) { - $bytes = @fread($fp, PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $rand = abs(hexdec($hex) % $lc); // random integer from 0 to $lc - $str .= $chars[$rand]; // random character in $chars - } - fclose($fp); - } else { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase("Please make sure you have 'openssl' extension installed") - ); + $charsMaxKey = mb_strlen($chars) - 1; + for ($i = 0; $i < $length; $i++) { + $str .= $chars[self::getRandomNumber(0, $charsMaxKey)]; } return $str; @@ -67,47 +53,33 @@ public function getRandomString($length, $chars = null) /** * Return a random number in the specified range * - * @param $min [optional] - * @param $max [optional] - * @return int A random integer value between min (or 0) and max - * @throws \Magento\Framework\Exception\LocalizedException + * @param int $min + * @param int $max + * @return int A random integer value between min (or 0) and max + * @throws LocalizedException */ public static function getRandomNumber($min = 0, $max = null) { if (null === $max) { $max = mt_getrandmax(); } - $range = $max - $min + 1; - $offset = 0; - if (function_exists('openssl_random_pseudo_bytes')) { - // use openssl lib if it is installed - $bytes = openssl_random_pseudo_bytes(PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $offset = abs(hexdec($hex) % $range); // random integer from 0 to $range - } elseif ($fp = @fopen('/dev/urandom', 'rb')) { - // attempt to use /dev/urandom if it exists but openssl isn't available - $bytes = @fread($fp, PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $offset = abs(hexdec($hex) % $range); // random integer from 0 to $range - fclose($fp); - } else { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase("Please make sure you have 'openssl' extension installed") - ); + if ($max < $min) { + throw new LocalizedException(new Phrase('Invalid range given.')); } - return $min + $offset; // random integer from $min to $max + return random_int($min, $max); } /** - * Generate a hash from unique ID + * Generate a hash from unique ID. * * @param string $prefix * @return string + * @throws LocalizedException */ public function getUniqueHash($prefix = '') { - return $prefix . md5(uniqid(microtime() . self::getRandomNumber(), true)); + return $prefix . $this->getRandomString(32); } } From 822de9dfbd4683ae7591779ac19a495b92118167 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 21 Sep 2018 15:59:25 +0300 Subject: [PATCH 052/118] MAGETWO-70943: Incorrect reset password flow --- .../Controller/Account/CreatePasswordTest.php | 233 -- .../Account/ResetPasswordPostTest.php | 379 --- .../Test/Unit/Model/AccountManagementTest.php | 2057 ----------------- 3 files changed, 2669 deletions(-) delete mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php delete mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php delete mode 100644 app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php deleted file mode 100644 index 77f41024ba02f..0000000000000 --- a/app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php +++ /dev/null @@ -1,233 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Customer\Test\Unit\Controller\Account; - -use Magento\Framework\Controller\Result\Redirect; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class CreatePasswordTest extends \PHPUnit\Framework\TestCase -{ - /** @var \Magento\Customer\Controller\Account\CreatePassword */ - protected $model; - - /** @var ObjectManagerHelper */ - protected $objectManagerHelper; - - /** @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject */ - protected $sessionMock; - - /** @var \Magento\Framework\View\Result\PageFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $pageFactoryMock; - - /** @var \Magento\Customer\Api\AccountManagementInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $accountManagementMock; - - /** @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $requestMock; - - /** @var \Magento\Framework\Controller\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $redirectFactoryMock; - - /** @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $messageManagerMock; - - protected function setUp() - { - $this->sessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods(['setRpToken', 'setRpCustomerId', 'getRpToken', 'getRpCustomerId']) - ->getMock(); - $this->pageFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Result\PageFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->accountManagementMock = $this->getMockBuilder(\Magento\Customer\Api\AccountManagementInterface::class) - ->getMockForAbstractClass(); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) - ->getMockForAbstractClass(); - $this->redirectFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) - ->getMockForAbstractClass(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $this->objectManagerHelper->getObject( - \Magento\Customer\Controller\Account\CreatePassword::class, - [ - 'customerSession' => $this->sessionMock, - 'resultPageFactory' => $this->pageFactoryMock, - 'accountManagement' => $this->accountManagementMock, - 'request' => $this->requestMock, - 'resultRedirectFactory' => $this->redirectFactoryMock, - 'messageManager' => $this->messageManagerMock, - ] - ); - } - - public function testExecuteWithLink() - { - $token = 'token'; - $customerId = '11'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getParam') - ->willReturnMap( - [ - ['token', null, $token], - ['id', null, $customerId], - ] - ); - - $this->accountManagementMock->expects($this->once()) - ->method('validateResetPasswordLinkToken') - ->with($customerId, $token) - ->willReturn(true); - - $this->sessionMock->expects($this->once()) - ->method('setRpToken') - ->with($token); - $this->sessionMock->expects($this->once()) - ->method('setRpCustomerId') - ->with($customerId); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createpassword', []) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithSession() - { - $token = 'token'; - $customerId = '11'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getParam') - ->willReturnMap( - [ - ['token', null, null], - ['id', null, $customerId], - ] - ); - - $this->sessionMock->expects($this->once()) - ->method('getRpToken') - ->willReturn($token); - $this->sessionMock->expects($this->once()) - ->method('getRpCustomerId') - ->willReturn($customerId); - - $this->accountManagementMock->expects($this->once()) - ->method('validateResetPasswordLinkToken') - ->with($customerId, $token) - ->willReturn(true); - - /** @var \Magento\Framework\View\Result\Page|\PHPUnit_Framework_MockObject_MockObject $pageMock */ - $pageMock = $this->getMockBuilder(\Magento\Framework\View\Result\Page::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->pageFactoryMock->expects($this->once()) - ->method('create') - ->with(false, []) - ->willReturn($pageMock); - - /** @var \Magento\Framework\View\Layout|\PHPUnit_Framework_MockObject_MockObject $layoutMock */ - $layoutMock = $this->getMockBuilder(\Magento\Framework\View\Layout::class) - ->disableOriginalConstructor() - ->getMock(); - - $pageMock->expects($this->once()) - ->method('getLayout') - ->willReturn($layoutMock); - - /** @var \Magento\Customer\Block\Account\Resetpassword|\PHPUnit_Framework_MockObject_MockObject $layoutMock */ - $blockMock = $this->getMockBuilder(\Magento\Customer\Block\Account\Resetpassword::class) - ->disableOriginalConstructor() - ->setMethods(['setCustomerId', 'setResetPasswordLinkToken']) - ->getMock(); - - $layoutMock->expects($this->once()) - ->method('getBlock') - ->with('resetPassword') - ->willReturn($blockMock); - - $blockMock->expects($this->once()) - ->method('setCustomerId') - ->with($customerId) - ->willReturnSelf(); - $blockMock->expects($this->once()) - ->method('setResetPasswordLinkToken') - ->with($token) - ->willReturnSelf(); - - $this->assertEquals($pageMock, $this->model->execute()); - } - - public function testExecuteWithException() - { - $token = 'token'; - $customerId = '11'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getParam') - ->willReturnMap( - [ - ['token', null, $token], - ['id', null, null], - ] - ); - - $this->sessionMock->expects($this->once()) - ->method('getRpToken') - ->willReturn($token); - $this->sessionMock->expects($this->once()) - ->method('getRpCustomerId') - ->willReturn($customerId); - - $this->accountManagementMock->expects($this->once()) - ->method('validateResetPasswordLinkToken') - ->with($customerId, $token) - ->willThrowException(new \Exception('Exception.')); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('Your password reset link has expired.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/forgotpassword', []) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } -} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php deleted file mode 100644 index b79ad008e5e44..0000000000000 --- a/app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php +++ /dev/null @@ -1,379 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Customer\Test\Unit\Controller\Account; - -use Magento\Framework\Controller\Result\Redirect; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class ResetPasswordPostTest extends \PHPUnit\Framework\TestCase -{ - /** @var \Magento\Customer\Controller\Account\ResetPasswordPost */ - protected $model; - - /** @var ObjectManagerHelper */ - protected $objectManagerHelper; - - /** @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject */ - protected $sessionMock; - - /** @var \Magento\Framework\View\Result\PageFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $pageFactoryMock; - - /** @var \Magento\Customer\Api\AccountManagementInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $accountManagementMock; - - /** @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerRepositoryMock; - - /** @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $requestMock; - - /** @var \Magento\Framework\Controller\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $redirectFactoryMock; - - /** @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $messageManagerMock; - - protected function setUp() - { - $this->sessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods(['unsRpToken', 'unsRpCustomerId']) - ->getMock(); - $this->pageFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Result\PageFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->accountManagementMock = $this->getMockBuilder(\Magento\Customer\Api\AccountManagementInterface::class) - ->getMockForAbstractClass(); - $this->customerRepositoryMock = $this->getMockBuilder(\Magento\Customer\Api\CustomerRepositoryInterface::class) - ->getMockForAbstractClass(); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) - ->setMethods(['getQuery', 'getPost']) - ->getMockForAbstractClass(); - $this->redirectFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) - ->getMockForAbstractClass(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $this->objectManagerHelper->getObject( - \Magento\Customer\Controller\Account\ResetPasswordPost::class, - [ - 'customerSession' => $this->sessionMock, - 'resultPageFactory' => $this->pageFactoryMock, - 'accountManagement' => $this->accountManagementMock, - 'customerRepository' => $this->customerRepositoryMock, - 'request' => $this->requestMock, - 'resultRedirectFactory' => $this->redirectFactoryMock, - 'messageManager' => $this->messageManagerMock, - ] - ); - } - - public function testExecute() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'password'; - $email = 'email@email.com'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $this->customerRepositoryMock->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($email); - - $this->accountManagementMock->expects($this->once()) - ->method('resetPassword') - ->with($email, $token, $password) - ->willReturn(true); - - $this->sessionMock->expects($this->once()) - ->method('unsRpToken'); - $this->sessionMock->expects($this->once()) - ->method('unsRpCustomerId'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') - ->with(__('You updated your password.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/login', []) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithException() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'password'; - $email = 'email@email.com'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $this->customerRepositoryMock->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($email); - - $this->accountManagementMock->expects($this->once()) - ->method('resetPassword') - ->with($email, $token, $password) - ->willThrowException(new \Exception('Exception.')); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('Something went wrong while saving the new password.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - /** - * Test for InputException - */ - public function testExecuteWithInputException() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'password'; - $email = 'email@email.com'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $this->customerRepositoryMock->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($email); - - $this->accountManagementMock->expects($this->once()) - ->method('resetPassword') - ->with($email, $token, $password) - ->willThrowException(new \Magento\Framework\Exception\InputException(__('InputException.'))); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('InputException.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithWrongConfirmation() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'wrong_password'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('New Password and Confirm New Password values didn\'t match.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithEmptyPassword() - { - $token = 'token'; - $customerId = '11'; - $password = ''; - $passwordConfirmation = ''; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('Please enter a new password.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } -} diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php deleted file mode 100644 index aad20f757e91e..0000000000000 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ /dev/null @@ -1,2057 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Customer\Test\Unit\Model; - -use Magento\Customer\Model\AccountManagement; -use Magento\Customer\Model\AccountConfirmation; -use Magento\Customer\Model\AuthenticationInterface; -use Magento\Customer\Model\EmailNotificationInterface; -use Magento\Framework\App\Area; -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\Intl\DateTimeFactory; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Store\Model\ScopeInterface; - -/** - * @SuppressWarnings(PHPMD.TooManyFields) - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class AccountManagementTest extends \PHPUnit\Framework\TestCase -{ - /** @var AccountManagement */ - protected $accountManagement; - - /** @var ObjectManagerHelper */ - protected $objectManagerHelper; - - /** @var \Magento\Customer\Model\CustomerFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerFactory; - - /** @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $manager; - - /** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $storeManager; - - /** @var \Magento\Framework\Math\Random|\PHPUnit_Framework_MockObject_MockObject */ - protected $random; - - /** @var \Magento\Customer\Model\Metadata\Validator|\PHPUnit_Framework_MockObject_MockObject */ - protected $validator; - - /** @var \Magento\Customer\Api\Data\ValidationResultsInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $validationResultsInterfaceFactory; - - /** @var \Magento\Customer\Api\AddressRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $addressRepository; - - /** @var \Magento\Customer\Api\CustomerMetadataInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerMetadata; - - /** @var \Magento\Customer\Model\CustomerRegistry|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerRegistry; - - /** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $logger; - - /** @var \Magento\Framework\Encryption\EncryptorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $encryptor; - - /** @var \Magento\Customer\Model\Config\Share|\PHPUnit_Framework_MockObject_MockObject */ - protected $share; - - /** @var \Magento\Framework\Stdlib\StringUtils|\PHPUnit_Framework_MockObject_MockObject */ - protected $string; - - /** @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerRepository; - - /** @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $scopeConfig; - - /** @var \Magento\Framework\Mail\Template\TransportBuilder|\PHPUnit_Framework_MockObject_MockObject */ - protected $transportBuilder; - - /** @var \Magento\Framework\Reflection\DataObjectProcessor|\PHPUnit_Framework_MockObject_MockObject */ - protected $dataObjectProcessor; - - /** @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject */ - protected $registry; - - /** @var \Magento\Customer\Helper\View|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerViewHelper; - - /** @var \Magento\Framework\Stdlib\DateTime|\PHPUnit_Framework_MockObject_MockObject */ - protected $dateTime; - - /** @var \Magento\Customer\Model\Customer|\PHPUnit_Framework_MockObject_MockObject */ - protected $customer; - - /** @var \Magento\Framework\DataObjectFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $objectFactory; - - /** @var \Magento\Framework\Api\ExtensibleDataObjectConverter|\PHPUnit_Framework_MockObject_MockObject */ - protected $extensibleDataObjectConverter; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\Store - */ - protected $store; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Customer\Model\Data\CustomerSecure - */ - protected $customerSecure; - - /** - * @var AuthenticationInterface |\PHPUnit_Framework_MockObject_MockObject - */ - protected $authenticationMock; - - /** - * @var EmailNotificationInterface |\PHPUnit_Framework_MockObject_MockObject - */ - protected $emailNotificationMock; - - /** - * @var DateTimeFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $dateTimeFactory; - - /** - * @var AccountConfirmation|\PHPUnit_Framework_MockObject_MockObject - */ - private $accountConfirmation; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Session\SessionManagerInterface - */ - private $sessionManager; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory - */ - private $visitorCollectionFactory; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Session\SaveHandlerInterface - */ - private $saveHandler; - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - protected function setUp() - { - $this->customerFactory = $this->createPartialMock(\Magento\Customer\Model\CustomerFactory::class, ['create']); - $this->manager = $this->createMock(\Magento\Framework\Event\ManagerInterface::class); - $this->store = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - $this->storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); - $this->random = $this->createMock(\Magento\Framework\Math\Random::class); - $this->validator = $this->createMock(\Magento\Customer\Model\Metadata\Validator::class); - $this->validationResultsInterfaceFactory = $this->createMock( - \Magento\Customer\Api\Data\ValidationResultsInterfaceFactory::class - ); - $this->addressRepository = $this->createMock(\Magento\Customer\Api\AddressRepositoryInterface::class); - $this->customerMetadata = $this->createMock(\Magento\Customer\Api\CustomerMetadataInterface::class); - $this->customerRegistry = $this->createMock(\Magento\Customer\Model\CustomerRegistry::class); - $this->logger = $this->createMock(\Psr\Log\LoggerInterface::class); - $this->encryptor = $this->createMock(\Magento\Framework\Encryption\EncryptorInterface::class); - $this->share = $this->createMock(\Magento\Customer\Model\Config\Share::class); - $this->string = $this->createMock(\Magento\Framework\Stdlib\StringUtils::class); - $this->customerRepository = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); - $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->transportBuilder = $this->createMock(\Magento\Framework\Mail\Template\TransportBuilder::class); - $this->dataObjectProcessor = $this->createMock(\Magento\Framework\Reflection\DataObjectProcessor::class); - $this->registry = $this->createMock(\Magento\Framework\Registry::class); - $this->customerViewHelper = $this->createMock(\Magento\Customer\Helper\View::class); - $this->dateTime = $this->createMock(\Magento\Framework\Stdlib\DateTime::class); - $this->customer = $this->createMock(\Magento\Customer\Model\Customer::class); - $this->objectFactory = $this->createMock(\Magento\Framework\DataObjectFactory::class); - $this->extensibleDataObjectConverter = $this->createMock( - \Magento\Framework\Api\ExtensibleDataObjectConverter::class - ); - $this->authenticationMock = $this->getMockBuilder(AuthenticationInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->emailNotificationMock = $this->getMockBuilder(EmailNotificationInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'addData', 'setRpTokenCreatedAt', 'setData']) - ->disableOriginalConstructor() - ->getMock(); - - $this->dateTimeFactory = $this->createMock(DateTimeFactory::class); - $this->accountConfirmation = $this->createMock(AccountConfirmation::class); - - $this->visitorCollectionFactory = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->accountManagement = $this->objectManagerHelper->getObject( - \Magento\Customer\Model\AccountManagement::class, - [ - 'customerFactory' => $this->customerFactory, - 'eventManager' => $this->manager, - 'storeManager' => $this->storeManager, - 'mathRandom' => $this->random, - 'validator' => $this->validator, - 'validationResultsDataFactory' => $this->validationResultsInterfaceFactory, - 'addressRepository' => $this->addressRepository, - 'customerMetadataService' => $this->customerMetadata, - 'customerRegistry' => $this->customerRegistry, - 'logger' => $this->logger, - 'encryptor' => $this->encryptor, - 'configShare' => $this->share, - 'stringHelper' => $this->string, - 'customerRepository' => $this->customerRepository, - 'scopeConfig' => $this->scopeConfig, - 'transportBuilder' => $this->transportBuilder, - 'dataProcessor' => $this->dataObjectProcessor, - 'registry' => $this->registry, - 'customerViewHelper' => $this->customerViewHelper, - 'dateTime' => $this->dateTime, - 'customerModel' => $this->customer, - 'objectFactory' => $this->objectFactory, - 'extensibleDataObjectConverter' => $this->extensibleDataObjectConverter, - 'dateTimeFactory' => $this->dateTimeFactory, - 'accountConfirmation' => $this->accountConfirmation, - 'sessionManager' => $this->sessionManager, - 'saveHandler' => $this->saveHandler, - 'visitorCollectionFactory' => $this->visitorCollectionFactory, - ] - ); - $this->objectManagerHelper->setBackwardCompatibleProperty( - $this->accountManagement, - 'authentication', - $this->authenticationMock - ); - $this->objectManagerHelper->setBackwardCompatibleProperty( - $this->accountManagement, - 'emailNotification', - $this->emailNotificationMock - ); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - */ - public function testCreateAccountWithPasswordHashWithExistingCustomer() - { - $websiteId = 1; - $storeId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->once()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->once()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\State\InputMismatchException - */ - public function testCreateAccountWithPasswordHashWithCustomerWithoutStoreId() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer - ->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer - ->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->atLeastOnce()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $exception = new \Magento\Framework\Exception\AlreadyExistsException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer, $hash) - ->willThrowException($exception); - - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashWithLocalizedException() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer - ->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer - ->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $exception = new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer, $hash) - ->willThrowException($exception); - - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashWithAddressException() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer - ->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer - ->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer, $hash) - ->willReturn($customer); - $exception = new \Magento\Framework\Exception\InputException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->addressRepository - ->expects($this->atLeastOnce()) - ->method('save') - ->with($address) - ->willThrowException($exception); - $this->customerRepository - ->expects($this->once()) - ->method('delete') - ->with($customer); - - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashWithNewCustomerAndLocalizedException() - { - $storeId = 1; - $storeName = 'store_name'; - $websiteId = 1; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $customerMock->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(null); - $customerMock->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customerMock->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customerMock->expects($this->once()) - ->method('setCreatedIn') - ->with($storeName) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('getAddresses') - ->willReturn([]); - $customerMock->expects($this->once()) - ->method('setAddresses') - ->with(null) - ->willReturnSelf(); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - - $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - - $storeMock->expects($this->once()) - ->method('getName') - ->willReturn($storeName); - - $this->storeManager->expects($this->exactly(1)) - ->method('getStore') - ->with($storeId) - ->willReturn($storeMock); - $exception = new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customerMock, $hash) - ->willThrowException($exception); - - $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testCreateAccountWithoutPassword() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $newLinkToken = '2jh43j5h2345jh23lh452h345hfuzasd96ofu'; - - $datetime = $this->prepareDateTimeFactory(); - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->atLeastOnce()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->addressRepository->expects($this->atLeastOnce()) - ->method('save') - ->with($address); - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($newLinkToken); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($newLinkToken); - $customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn(null); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - $this->emailNotificationMock->expects($this->once()) - ->method('newAccount') - ->willReturnSelf(); - - $this->accountManagement->createAccount($customer); - } - - /** - * Data provider for testCreateAccountWithPasswordInputException test - * - * @return array - */ - public function dataProviderCheckPasswordStrength() - { - return [ - [ - 'testNumber' => 1, - 'password' => 'qwer', - 'minPasswordLength' => 5, - 'minCharacterSetsNum' => 1, - ], - [ - 'testNumber' => 2, - 'password' => 'wrfewqedf1', - 'minPasswordLength' => 5, - 'minCharacterSetsNum' => 3, - ], - ]; - } - - /** - * @param int $testNumber - * @param string $password - * @param int $minPasswordLength - * @param int $minCharacterSetsNum - * @dataProvider dataProviderCheckPasswordStrength - */ - public function testCreateAccountWithPasswordInputException( - $testNumber, - $password, - $minPasswordLength, - $minCharacterSetsNum - ) { - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->will( - $this->returnValueMap( - [ - [ - AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH, - 'default', - null, - $minPasswordLength, - ], - [ - AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, - 'default', - null, - $minCharacterSetsNum, - ], - ] - ) - ); - - $this->string->expects($this->any()) - ->method('strlen') - ->with($password) - ->willReturn(iconv_strlen($password, 'UTF-8')); - - if ($testNumber == 1) { - $this->expectException(\Magento\Framework\Exception\InputException::class); - $this->expectExceptionMessage('The password needs at least ' . $minPasswordLength . ' characters. ' - . 'Create a new password and try again.'); - } - - if ($testNumber == 2) { - $this->expectException(\Magento\Framework\Exception\InputException::class); - $this->expectExceptionMessage('Minimum of different classes of characters in password is ' . - $minCharacterSetsNum . '. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.'); - } - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $this->accountManagement->createAccount($customer, $password); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountInputExceptionExtraLongPassword() - { - $password = '257*chars*************************************************************************************' - . '****************************************************************************************************' - . '***************************************************************'; - - $this->string->expects($this->any()) - ->method('strlen') - ->with($password) - ->willReturn(iconv_strlen($password, 'UTF-8')); - - $this->expectException(\Magento\Framework\Exception\InputException::class); - $this->expectExceptionMessage('Please enter a password with at most 256 characters.'); - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $this->accountManagement->createAccount($customer, $password); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testCreateAccountWithPassword() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - $newLinkToken = '2jh43j5h2345jh23lh452h345hfuzasd96ofu'; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - $password = 'wrfewqedf1'; - $minPasswordLength = 5; - $minCharacterSetsNum = 2; - - $datetime = $this->prepareDateTimeFactory(); - - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->willReturnMap( - [ - [ - AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH, - 'default', - null, - $minPasswordLength, - ], - [ - AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, - 'default', - null, - $minCharacterSetsNum, - ], - [ - AccountManagement::XML_PATH_REGISTER_EMAIL_TEMPLATE, - ScopeInterface::SCOPE_STORE, - $defaultStoreId, - $templateIdentifier, - ], - [ - AccountManagement::XML_PATH_REGISTER_EMAIL_IDENTITY, - ScopeInterface::SCOPE_STORE, - 1, - $sender, - ], - ] - ); - $this->string->expects($this->any()) - ->method('strlen') - ->with($password) - ->willReturn(iconv_strlen($password, 'UTF-8')); - $this->encryptor->expects($this->once()) - ->method('getHash') - ->with($password, true) - ->willReturn($hash); - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->atLeastOnce()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->addressRepository->expects($this->atLeastOnce()) - ->method('save') - ->with($address); - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($newLinkToken); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($newLinkToken); - $customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($hash); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - $this->emailNotificationMock->expects($this->once()) - ->method('newAccount') - ->willReturnSelf(); - - $this->accountManagement->createAccount($customer, $password); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testSendPasswordReminderEmail() - { - $customerId = 1; - $customerStoreId = 2; - $customerEmail = 'email@email.com'; - $customerData = ['key' => 'value']; - $customerName = 'Customer Name'; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - $customer->expects($this->any()) - ->method('getStoreId') - ->willReturn($customerStoreId); - $customer->expects($this->any()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->any()) - ->method('getEmail') - ->willReturn($customerEmail); - - $this->store->expects($this->any()) - ->method('getId') - ->willReturn($customerStoreId); - - $this->storeManager->expects($this->at(0)) - ->method('getStore') - ->willReturn($this->store); - - $this->storeManager->expects($this->at(1)) - ->method('getStore') - ->with($customerStoreId) - ->willReturn($this->store); - - $this->customerRegistry->expects($this->once()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($this->customerSecure); - - $this->dataObjectProcessor->expects($this->once()) - ->method('buildOutputDataArray') - ->with($customer, \Magento\Customer\Api\Data\CustomerInterface::class) - ->willReturn($customerData); - - $this->customerViewHelper->expects($this->any()) - ->method('getCustomerName') - ->with($customer) - ->willReturn($customerName); - - $this->customerSecure->expects($this->once()) - ->method('addData') - ->with($customerData) - ->willReturnSelf(); - $this->customerSecure->expects($this->once()) - ->method('setData') - ->with('name', $customerName) - ->willReturnSelf(); - - $this->scopeConfig->expects($this->at(0)) - ->method('getValue') - ->with(AccountManagement::XML_PATH_REMIND_EMAIL_TEMPLATE, ScopeInterface::SCOPE_STORE, $customerStoreId) - ->willReturn($templateIdentifier); - $this->scopeConfig->expects($this->at(1)) - ->method('getValue') - ->with(AccountManagement::XML_PATH_FORGOT_EMAIL_IDENTITY, ScopeInterface::SCOPE_STORE, $customerStoreId) - ->willReturn($sender); - - $transport = $this->getMockBuilder(\Magento\Framework\Mail\TransportInterface::class) - ->getMock(); - - $this->transportBuilder->expects($this->once()) - ->method('setTemplateIdentifier') - ->with($templateIdentifier) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('setTemplateOptions') - ->with(['area' => Area::AREA_FRONTEND, 'store' => $customerStoreId]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('setTemplateVars') - ->with(['customer' => $this->customerSecure, 'store' => $this->store]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('setFrom') - ->with($sender) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('addTo') - ->with($customerEmail, $customerName) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('getTransport') - ->willReturn($transport); - - $transport->expects($this->once()) - ->method('sendMessage'); - - $this->assertEquals($this->accountManagement, $this->accountManagement->sendPasswordReminderEmail($customer)); - } - - /** - * @param string $email - * @param string $templateIdentifier - * @param string $sender - * @param int $storeId - * @param int $customerId - * @param string $hash - */ - protected function prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash) - { - $websiteId = 1; - - $datetime = $this->prepareDateTimeFactory(); - - $customerData = ['key' => 'value']; - $customerName = 'Customer Name'; - - $this->store->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $this->store->expects($this->any()) - ->method('getId') - ->willReturn($storeId); - - $this->storeManager->expects($this->any()) - ->method('getStore') - ->willReturn($this->store); - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - $customer->expects($this->any()) - ->method('getEmail') - ->willReturn($email); - $customer->expects($this->any()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->any()) - ->method('getStoreId') - ->willReturn($storeId); - - $this->customerRepository->expects($this->once()) - ->method('get') - ->with($email, $websiteId) - ->willReturn($customer); - $this->customerRepository->expects($this->once()) - ->method('save') - ->with($customer) - ->willReturnSelf(); - - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($hash); - - $this->customerViewHelper->expects($this->any()) - ->method('getCustomerName') - ->with($customer) - ->willReturn($customerName); - - $this->customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($hash) - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('addData') - ->with($customerData) - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('setData') - ->with('name', $customerName) - ->willReturnSelf(); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($this->customerSecure); - - $this->dataObjectProcessor->expects($this->any()) - ->method('buildOutputDataArray') - ->with($customer, \Magento\Customer\Api\Data\CustomerInterface::class) - ->willReturn($customerData); - - $this->prepareEmailSend($email, $templateIdentifier, $sender, $storeId, $customerName); - } - - /** - * @param string $email - * @param int $templateIdentifier - * @param string $sender - * @param int $storeId - * @param string $customerName - */ - protected function prepareEmailSend($email, $templateIdentifier, $sender, $storeId, $customerName) - { - $transport = $this->getMockBuilder(\Magento\Framework\Mail\TransportInterface::class) - ->getMock(); - - $this->transportBuilder->expects($this->any()) - ->method('setTemplateIdentifier') - ->with($templateIdentifier) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('setTemplateOptions') - ->with(['area' => Area::AREA_FRONTEND, 'store' => $storeId]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('setTemplateVars') - ->with(['customer' => $this->customerSecure, 'store' => $this->store]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('setFrom') - ->with($sender) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('addTo') - ->with($email, $customerName) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('getTransport') - ->willReturn($transport); - - $transport->expects($this->any()) - ->method('sendMessage'); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testInitiatePasswordResetEmailReminder() - { - $customerId = 1; - - $email = 'test@example.com'; - $template = AccountManagement::EMAIL_REMINDER; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - $storeId = 1; - - mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); - $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); - - $this->emailNotificationMock->expects($this->once()) - ->method('passwordReminder') - ->willReturnSelf(); - - $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); - - $this->assertTrue($this->accountManagement->initiatePasswordReset($email, $template)); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testInitiatePasswordResetEmailReset() - { - $storeId = 1; - $customerId = 1; - - $email = 'test@example.com'; - $template = AccountManagement::EMAIL_RESET; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); - $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); - - $this->emailNotificationMock->expects($this->once()) - ->method('passwordResetConfirmation') - ->willReturnSelf(); - - $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); - - $this->assertTrue($this->accountManagement->initiatePasswordReset($email, $template)); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testInitiatePasswordResetNoTemplate() - { - $storeId = 1; - $customerId = 1; - - $email = 'test@example.com'; - $template = null; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); - $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); - - $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); - - $this->expectException(\Magento\Framework\Exception\InputException::class); - $this->expectExceptionMessage( - 'Invalid value of "" provided for the template field. Possible values: email_reminder or email_reset.' - ); - $this->accountManagement->initiatePasswordReset($email, $template); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage Invalid value of "" provided for the customerId field - */ - public function testValidateResetPasswordTokenBadCustomerId() - { - $this->accountManagement->validateResetPasswordLinkToken(null, ''); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage "resetPasswordLinkToken" is required. Enter and try again. - */ - public function testValidateResetPasswordTokenBadResetPasswordLinkToken() - { - $this->accountManagement->validateResetPasswordLinkToken(22, null); - } - - /** - * @expectedException \Magento\Framework\Exception\State\InputMismatchException - * @expectedExceptionMessage The password token is mismatched. Reset and try again. - */ - public function testValidateResetPasswordTokenTokenMismatch() - { - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->accountManagement->validateResetPasswordLinkToken(22, 'newStringToken'); - } - - /** - * @expectedException \Magento\Framework\Exception\State\ExpiredException - * @expectedExceptionMessage The password token is expired. Reset and try again. - */ - public function testValidateResetPasswordTokenTokenExpired() - { - $this->reInitModel(); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->accountManagement->validateResetPasswordLinkToken(22, 'newStringToken'); - } - - /** - * return bool - */ - public function testValidateResetPasswordToken() - { - $this->reInitModel(); - - $this->customer - ->expects($this->once()) - ->method('getResetPasswordLinkExpirationPeriod') - ->willReturn(100000); - - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->assertTrue($this->accountManagement->validateResetPasswordLinkToken(22, 'newStringToken')); - } - - /** - * reInit $this->accountManagement object - */ - private function reInitModel() - { - $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->disableOriginalConstructor() - ->setMethods( - [ - 'getRpToken', - 'getRpTokenCreatedAt', - 'getPasswordHash', - 'setPasswordHash', - 'setRpToken', - 'setRpTokenCreatedAt', - ] - ) - ->getMock(); - $this->customerSecure->expects($this->any()) - ->method('getRpToken') - ->willReturn('newStringToken'); - $pastDateTime = '2016-10-25 00:00:00'; - $this->customerSecure->expects($this->any()) - ->method('getRpTokenCreatedAt') - ->willReturn($pastDateTime); - $this->customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) - ->disableOriginalConstructor() - ->setMethods(['getResetPasswordLinkExpirationPeriod']) - ->getMock(); - - $this->prepareDateTimeFactory(); - $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->visitorCollectionFactory = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) - ->disableOriginalConstructor() - ->setMethods(['destroy']) - ->getMockForAbstractClass(); - - $dateTime = '2017-10-25 18:57:08'; - $timestamp = '1508983028'; - $dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->disableOriginalConstructor() - ->setMethods(['format', 'getTimestamp', 'setTimestamp']) - ->getMock(); - - $dateTimeMock->expects($this->any()) - ->method('format') - ->with(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT) - ->willReturn($dateTime); - $dateTimeMock->expects($this->any()) - ->method('getTimestamp') - ->willReturn($timestamp); - $dateTimeMock->expects($this->any()) - ->method('setTimestamp') - ->willReturnSelf(); - $dateTimeFactory = $this->getMockBuilder(DateTimeFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $dateTimeFactory->expects($this->any())->method('create')->willReturn($dateTimeMock); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->accountManagement = $this->objectManagerHelper->getObject( - \Magento\Customer\Model\AccountManagement::class, - [ - 'customerFactory' => $this->customerFactory, - 'customerRegistry' => $this->customerRegistry, - 'customerRepository' => $this->customerRepository, - 'customerModel' => $this->customer, - 'dateTimeFactory' => $dateTimeFactory, - 'stringHelper' => $this->string, - 'scopeConfig' => $this->scopeConfig, - 'sessionManager' => $this->sessionManager, - 'visitorCollectionFactory' => $this->visitorCollectionFactory, - 'saveHandler' => $this->saveHandler, - 'encryptor' => $this->encryptor, - 'dataProcessor' => $this->dataObjectProcessor, - 'storeManager' => $this->storeManager, - 'transportBuilder' => $this->transportBuilder, - ] - ); - $this->objectManagerHelper->setBackwardCompatibleProperty( - $this->accountManagement, - 'authentication', - $this->authenticationMock - ); - } - - /** - * @return void - */ - public function testChangePassword() - { - $customerId = 7; - $email = 'test@example.com'; - $currentPassword = '1234567'; - $newPassword = 'abcdefg'; - $passwordHash = '1a2b3f4c'; - - $this->reInitModel(); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - $customer->expects($this->any()) - ->method('getId') - ->willReturn($customerId); - - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($email) - ->willReturn($customer); - - $this->authenticationMock->expects($this->once()) - ->method('authenticate'); - - $this->customerSecure->expects($this->once()) - ->method('setRpToken') - ->with(null); - $this->customerSecure->expects($this->once()) - ->method('setRpTokenCreatedAt') - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($passwordHash); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($this->customerSecure); - - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->willReturnMap( - [ - [ - AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH, - 'default', - null, - 7, - ], - [ - AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, - 'default', - null, - 1, - ], - ] - ); - $this->string->expects($this->any()) - ->method('strlen') - ->with($newPassword) - ->willReturn(7); - - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer); - - $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); - - $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) - ->disableOriginalConstructor() - ->setMethods(['getSessionId']) - ->getMock(); - $visitor->expects($this->atLeastOnce())->method('getSessionId') - ->willReturnOnConsecutiveCalls('session_id_1', 'session_id_2'); - $visitorCollection = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); - $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); - $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); - $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') - ->willReturn($visitorCollection); - $this->saveHandler->expects($this->atLeastOnce())->method('destroy') - ->withConsecutive( - ['session_id_1'], - ['session_id_2'] - ); - - $this->assertTrue($this->accountManagement->changePassword($email, $currentPassword, $newPassword)); - } - - /** - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function testResetPassword() - { - $customerEmail = 'customer@example.com'; - $customerId = '1'; - $resetToken = 'newStringToken'; - $newPassword = 'new_password'; - - $this->reInitModel(); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->any())->method('getId')->willReturn($customerId); - $this->customerRepository->expects($this->atLeastOnce())->method('get')->with($customerEmail) - ->willReturn($customer); - $this->customer->expects($this->atLeastOnce())->method('getResetPasswordLinkExpirationPeriod') - ->willReturn(100000); - $this->string->expects($this->any())->method('strlen')->willReturnCallback( - function ($string) { - return strlen($string); - } - ); - $this->customerRegistry->expects($this->atLeastOnce())->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->customerSecure->expects($this->once())->method('setRpToken')->with(null); - $this->customerSecure->expects($this->once())->method('setRpTokenCreatedAt')->with(null); - $this->customerSecure->expects($this->any())->method('setPasswordHash')->willReturn(null); - - $this->sessionManager->expects($this->atLeastOnce())->method('destroy'); - $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); - $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) - ->disableOriginalConstructor() - ->setMethods(['getSessionId']) - ->getMock(); - $visitor->expects($this->atLeastOnce())->method('getSessionId') - ->willReturnOnConsecutiveCalls('session_id_1', 'session_id_2'); - $visitorCollection = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); - $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); - $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); - $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') - ->willReturn($visitorCollection); - $this->saveHandler->expects($this->atLeastOnce())->method('destroy') - ->withConsecutive( - ['session_id_1'], - ['session_id_2'] - ); - $this->assertTrue($this->accountManagement->resetPassword($customerEmail, $resetToken, $newPassword)); - } - - /** - * @return void - */ - public function testChangePasswordException() - { - $email = 'test@example.com'; - $currentPassword = '1234567'; - $newPassword = 'abcdefg'; - - $exception = new NoSuchEntityException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($email) - ->willThrowException($exception); - - $this->expectException(\Magento\Framework\Exception\InvalidEmailOrPasswordException::class); - $this->expectExceptionMessage('Invalid login or password.'); - - $this->accountManagement->changePassword($email, $currentPassword, $newPassword); - } - - /** - * @return void - */ - public function testAuthenticate() - { - $username = 'login'; - $password = '1234567'; - $passwordHash = '1a2b3f4c'; - - $customerData = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - - $customerModel = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) - ->disableOriginalConstructor() - ->getMock(); - $customerModel->expects($this->once()) - ->method('updateData') - ->willReturn($customerModel); - - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($username) - ->willReturn($customerData); - - $this->authenticationMock->expects($this->once()) - ->method('authenticate'); - - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($passwordHash); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - - $this->customerFactory->expects($this->once()) - ->method('create') - ->willReturn($customerModel); - - $this->manager->expects($this->exactly(2)) - ->method('dispatch') - ->withConsecutive( - [ - 'customer_customer_authenticated', - ['model' => $customerModel, 'password' => $password], - ], - [ - 'customer_data_object_login', ['customer' => $customerData], - ] - ); - - $this->assertEquals($customerData, $this->accountManagement->authenticate($username, $password)); - } - - /** - * @param int $isConfirmationRequired - * @param string|null $confirmation - * @param string $expected - * @dataProvider dataProviderGetConfirmationStatus - */ - public function testGetConfirmationStatus( - $isConfirmationRequired, - $confirmation, - $expected - ) { - $websiteId = 1; - $customerId = 1; - $customerEmail = 'test1@example.com'; - - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $customerMock->expects($this->once()) - ->method('getId') - ->willReturn($customerId); - $customerMock->expects($this->any()) - ->method('getConfirmation') - ->willReturn($confirmation); - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customerMock->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - - $this->accountConfirmation->expects($this->once()) - ->method('isConfirmationRequired') - ->with($websiteId, $customerId, $customerEmail) - ->willReturn($isConfirmationRequired); - - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $this->assertEquals($expected, $this->accountManagement->getConfirmationStatus($customerId)); - } - - /** - * @return array - */ - public function dataProviderGetConfirmationStatus() - { - return [ - [0, null, AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED], - [0, null, AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED], - [0, null, AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED], - [1, null, AccountManagement::ACCOUNT_CONFIRMED], - [1, 'test', AccountManagement::ACCOUNT_CONFIRMATION_REQUIRED], - ]; - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashForGuest() - { - $storeId = 1; - $storeName = 'store_name'; - $websiteId = 1; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - $storeMock->expects($this->once()) - ->method('getId') - ->willReturn($storeId); - $storeMock->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $storeMock->expects($this->once()) - ->method('getName') - ->willReturn($storeName); - - $this->storeManager->expects($this->exactly(3)) - ->method('getStore') - ->willReturn($storeMock); - - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - $customerMock->expects($this->exactly(2)) - ->method('getId') - ->willReturn(null); - $customerMock->expects($this->exactly(3)) - ->method('getStoreId') - ->willReturn(null); - $customerMock->expects($this->exactly(3)) - ->method('getWebsiteId') - ->willReturn(null); - $customerMock->expects($this->once()) - ->method('setStoreId') - ->with($storeId) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('setWebsiteId') - ->with($websiteId) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('setCreatedIn') - ->with($storeName) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('getAddresses') - ->willReturn(null); - $customerMock->expects($this->once()) - ->method('setAddresses') - ->with(null) - ->willReturnSelf(); - - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customerMock, $hash) - ->willThrowException(new \Magento\Framework\Exception\LocalizedException(__('Exception message'))); - - $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testCreateAccountWithPasswordHashWithCustomerAddresses() - { - $websiteId = 1; - $addressId = 2; - $customerId = null; - $storeId = 1; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $this->prepareDateTimeFactory(); - - //Handle store - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->any()) - ->method('getWebsiteId') - ->willReturn($websiteId); - //Handle address - existing and non-existing. Non-Existing should return null when call getId method - $existingAddress = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $nonExistingAddress = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - //Ensure that existing address is not in use - $this->addressRepository - ->expects($this->atLeastOnce()) - ->method("save") - ->withConsecutive( - [$this->logicalNot($this->identicalTo($existingAddress))], - [$this->identicalTo($nonExistingAddress)] - ); - - $existingAddress - ->expects($this->any()) - ->method("getId") - ->willReturn($addressId); - //Expects that id for existing address should be unset - $existingAddress - ->expects($this->once()) - ->method("setId") - ->with(null); - //Handle Customer calls - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer - ->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer - ->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer - ->expects($this->any()) - ->method("getId") - ->willReturn($customerId); - //Return Customer from customer repository - $this->customerRepository - ->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->customerRepository - ->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->once()) - ->method('setRpToken') - ->with($hash); - - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($hash); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($customerSecure); - - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($hash); - - $customer - ->expects($this->atLeastOnce()) - ->method('getAddresses') - ->willReturn([$existingAddress, $nonExistingAddress]); - - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getStore') - ->willReturn($store); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - - $this->assertSame($customer, $this->accountManagement->createAccountWithPasswordHash($customer, $hash)); - } - - /** - * @return string - */ - private function prepareDateTimeFactory() - { - $dateTime = '2017-10-25 18:57:08'; - $timestamp = '1508983028'; - $dateTimeMock = $this->createMock(\DateTime::class); - $dateTimeMock->expects($this->any()) - ->method('format') - ->with(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT) - ->willReturn($dateTime); - - $dateTimeMock - ->expects($this->any()) - ->method('getTimestamp') - ->willReturn($timestamp); - - $this->dateTimeFactory - ->expects($this->any()) - ->method('create') - ->willReturn($dateTimeMock); - - return $dateTime; - } - - /** - * @return void - */ - public function testCreateAccountUnexpectedValueException(): void - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $newLinkToken = '2jh43j5h2345jh23lh452h345hfuzasd96ofu'; - $exception = new \UnexpectedValueException('Template file was not found'); - - $datetime = $this->prepareDateTimeFactory(); - - $address = $this->createMock(\Magento\Customer\Api\Data\AddressInterface::class); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->createMock(\Magento\Store\Model\Store::class); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->createMock(\Magento\Store\Model\Website::class); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->atLeastOnce()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->addressRepository->expects($this->atLeastOnce()) - ->method('save') - ->with($address); - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($newLinkToken); - $customerSecure = $this->createPartialMock( - \Magento\Customer\Model\Data\CustomerSecure::class, - ['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash'] - ); - $customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($newLinkToken); - $customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn(null); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - $this->emailNotificationMock->expects($this->once()) - ->method('newAccount') - ->willThrowException($exception); - $this->logger->expects($this->once())->method('error')->with($exception); - - $this->accountManagement->createAccount($customer); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithStoreNotInWebsite() - { - $storeId = 1; - $websiteId = 1; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - $customerMock->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(null); - $customerMock->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customerMock->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([2, 3]); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); - } -} From e41cd3a5aef2c0620f05b758dc6852ceb46785d8 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 21 Sep 2018 16:09:39 +0300 Subject: [PATCH 053/118] MAGETWO-70943: Incorrect reset password flow --- app/code/Magento/Customer/Model/AccountManagement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 52264c78b7717..6aee2894f4907 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -661,7 +661,7 @@ private function handleUnknownTemplate($template) /** * @inheritdoc */ - public function resetPassword(?string $email, string $resetToken, string $newPassword): bool + public function resetPassword($email, $resetToken, $newPassword): bool { if (!$email) { $customer = $this->matchCustomerByRpToken($resetToken); From 63d33c5081068ca8253e52763fb8ab7d5ffe8a1a Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Fri, 21 Sep 2018 15:08:49 -0500 Subject: [PATCH 054/118] MAGETWO-90280: Could not create customer via API without store_id --- .../Customer/Model/AccountManagement.php | 1 + .../Customer/Api/AccountManagementTest.php | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index fe17adcb09c0d..3d88aeaef767b 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -781,6 +781,7 @@ public function createAccountWithPasswordHash(CustomerInterface $customer, $hash if ($customer->getWebsiteId()) { $storeId = $this->storeManager->getWebsite($customer->getWebsiteId())->getDefaultStore()->getId(); } else { + $this->storeManager->setCurrentStore(null); $storeId = $this->storeManager->getStore()->getId(); } $customer->setStoreId($storeId); diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php index b0d1647d8b837..b2276d79f5ecf 100644 --- a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php @@ -213,6 +213,34 @@ public function testCreateCustomerWithErrors() } } + public function testCreateCustomerWithoutOptionalFields() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'CreateAccount', + ], + ]; + + $customerDataArray = $this->dataObjectProcessor->buildOutputDataArray( + $this->customerHelper->createSampleCustomerDataObject(), + \Magento\Customer\Api\Data\CustomerInterface::class + ); + unset($customerDataArray['store_id']); + unset($customerDataArray['website_id']); + $requestData = ['customer' => $customerDataArray, 'password' => CustomerHelper::PASSWORD]; + try { + $customerData = $this->_webApiCall($serviceInfo, $requestData, null, 'all'); + $this->assertNotNull($customerData['id']); + } catch (\Exception $e) { + $this->fail('Customer should be created without optional fields.'); + } + } + /** * Test customer activation when it is required * From bc2f6f5f25f45ad043f4daaf4882960c45f68213 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Mon, 24 Sep 2018 11:53:02 -0500 Subject: [PATCH 055/118] MAGETWO-90280: Could not create customer via API without store_id - fix static tests --- app/code/Magento/Customer/Model/AccountManagement.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 3d88aeaef767b..94c18b2cd56f8 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -956,6 +956,8 @@ protected function createPasswordHash($password) } /** + * Get EAV validator + * * @return Backend */ private function getEavValidator() @@ -1154,6 +1156,8 @@ protected function getWebsiteStoreId($customer, $defaultStoreId = null) } /** + * Get template types + * * @return array * @deprecated 100.1.0 */ From 56f0c1b18ddf0e5afd2f32a4d23c2e679f33727a Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Mon, 24 Sep 2018 16:17:12 -0500 Subject: [PATCH 056/118] MAGETWO-87333: Broken Mainline Test Magento\Paypal\Controller\ExpressTest::testReturnAction - Unskip test to validate stability on Jenkins --- .../testsuite/Magento/Paypal/Controller/ExpressTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php index 3d30f8366598a..157999224d7b8 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php @@ -140,12 +140,11 @@ public function testStartActionCustomerToQuote() /** * Test return action with configurable product. + * + * @magentoDataFixture Magento/Paypal/_files/quote_express_configurable.php */ public function testReturnAction() { - // Skipped due to MAGETWO-87333 - //@magentoDataFixture Magento/Paypal/_files/quote_express_configurable.php - $this->markTestSkipped('MAGETWO-87333'); $quote = $this->_objectManager->create(Quote::class); $quote->load('test_cart_with_configurable', 'reserved_order_id'); From 3aec1d71b23328e62b07bdb58ea22d6476bc2599 Mon Sep 17 00:00:00 2001 From: Cari Spruiell <spruiell@adobe.com> Date: Tue, 25 Sep 2018 16:35:51 -0500 Subject: [PATCH 057/118] MC-4259: Fix Skipped MTF Test CreateWidgetHierarchyNodeLinkTestVariation2_0 - remove page override and update selector to be compatible with core & PB pages --- .../functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml index 22d29eae1656b..1a7adcd531c55 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml @@ -7,6 +7,6 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/pages.xsd"> <page name="CmsPage" mca="cms/page" module="Magento_Cms"> - <block name="cmsPageBlock" class="Magento\Cms\Test\Block\Page" locator=".page-main" strategy="css selector" /> + <block name="cmsPageBlock" class="Magento\Cms\Test\Block\Page" locator="#maincontent" strategy="css selector" /> </page> </config> From 073ca97b102143b1ea13bb4a910eb1d426ee78bb Mon Sep 17 00:00:00 2001 From: Roman Ganin <rganin@adobe.com> Date: Tue, 25 Sep 2018 16:37:26 -0500 Subject: [PATCH 058/118] MAGETWO-95035: Multi-master splitting works for the core tables (created through declarative schema) but not for tables created with setup scripts --- app/code/Magento/SalesRule/etc/db_schema.xml | 4 ++-- app/code/Magento/Tax/etc/db_schema.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/SalesRule/etc/db_schema.xml b/app/code/Magento/SalesRule/etc/db_schema.xml index 3d882ee2eae67..cdbd50c3f3472 100644 --- a/app/code/Magento/SalesRule/etc/db_schema.xml +++ b/app/code/Magento/SalesRule/etc/db_schema.xml @@ -198,7 +198,7 @@ <column name="attribute_id"/> </index> </table> - <table name="salesrule_coupon_aggregated" resource="default" engine="innodb" comment="Coupon Aggregated"> + <table name="salesrule_coupon_aggregated" resource="sales" engine="innodb" comment="Coupon Aggregated"> <column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true" comment="Id"/> <column xsi:type="date" name="period" nullable="false" comment="Period"/> <column xsi:type="smallint" name="store_id" padding="5" unsigned="true" nullable="true" identity="false" @@ -239,7 +239,7 @@ <column name="rule_name"/> </index> </table> - <table name="salesrule_coupon_aggregated_updated" resource="default" engine="innodb" + <table name="salesrule_coupon_aggregated_updated" resource="sales" engine="innodb" comment="Salesrule Coupon Aggregated Updated"> <column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true" comment="Id"/> <column xsi:type="date" name="period" nullable="false" comment="Period"/> diff --git a/app/code/Magento/Tax/etc/db_schema.xml b/app/code/Magento/Tax/etc/db_schema.xml index 6cc4041f75a6d..6e83a64791969 100644 --- a/app/code/Magento/Tax/etc/db_schema.xml +++ b/app/code/Magento/Tax/etc/db_schema.xml @@ -139,7 +139,7 @@ <column name="store_id"/> </index> </table> - <table name="tax_order_aggregated_created" resource="default" engine="innodb" comment="Tax Order Aggregation"> + <table name="tax_order_aggregated_created" resource="sales" engine="innodb" comment="Tax Order Aggregation"> <column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true" comment="Id"/> <column xsi:type="date" name="period" comment="Period"/> <column xsi:type="smallint" name="store_id" padding="5" unsigned="true" nullable="true" identity="false" @@ -168,7 +168,7 @@ <column name="store_id"/> </index> </table> - <table name="tax_order_aggregated_updated" resource="default" engine="innodb" + <table name="tax_order_aggregated_updated" resource="sales" engine="innodb" comment="Tax Order Aggregated Updated"> <column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true" comment="Id"/> <column xsi:type="date" name="period" comment="Period"/> From e2370ace78e463a9ae128e4f75b05993f261c25c Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Wed, 26 Sep 2018 11:01:03 -0500 Subject: [PATCH 059/118] MAGETWO-94819: Swatch validation breaks the whole attribute form - add jquery form validation event to restore options container --- app/code/Magento/Catalog/view/adminhtml/web/js/options.js | 2 +- .../Swatches/view/adminhtml/web/js/product-attributes.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js index 7c35993670444..1ec47f14fee88 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js @@ -210,7 +210,7 @@ define([ } tableBody = optionContainer.detach(); }); - editForm.on('afterValidate.error', function () { + editForm.on('afterValidate.error highlight.validate', function () { if (optionPanel.hasClass(activePanelClass)) { optionPanel.find('table').append(tableBody); jQuery('input[name="serialized_options"]').remove(); diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index d0eacc94e2c32..1dc833d5901ca 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -463,7 +463,7 @@ define([ tableBody = optionContainer.detach(); }); - editForm.on('afterValidate.error', function () { + editForm.on('afterValidate.error highlight.validate', function () { if (activePanel.hasClass(activePanelClass)) { activePanel.find('table').append(tableBody); $('input[name="serialized_options"]').remove(); From f0b1e02fb4cd9bc8be17a05469f3d10749d2b423 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Wed, 26 Sep 2018 15:07:47 -0500 Subject: [PATCH 060/118] MC-4277: Address Product Page slowness due to 'product_data_storage' handling --- .../view/frontend/web/js/product/storage/data-storage.js | 2 +- .../view/frontend/web/js/product/storage/ids-storage.js | 6 +----- .../view/frontend/web/js/product/storage/storage-service.js | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js index ab566a70a756d..0059cee60d30f 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js @@ -118,7 +118,7 @@ define([ if (_.isEmpty(data)) { this.localStorage.removeAll(); } else { - this.localStorage.set(data); + window.localStorage.setItem(this.namespace, JSON.stringify(data)); } }, diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js index 7eafbad8299d8..f77bdd0263aa7 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js @@ -94,11 +94,7 @@ define([ * Initializes handler to "data" property update */ internalDataHandler: function (data) { - var localStorage = this.localStorage.get(); - - if (!utils.compare(data, localStorage).equal) { - this.localStorage.set(data); - } + window.localStorage.setItem(this.namespace, JSON.stringify(data)); }, /** diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js index e571baa23e497..b35ab867bb0e7 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js @@ -47,7 +47,7 @@ define([ * @param {*} data */ add: function (data) { - if (!_.isEmpty(data) && !utils.compare(data, this.data()).equal) { + if (!_.isEmpty(data)) { this.data(_.extend(utils.copy(this.data()), data)); } }, From 9b7f45add2d5fbcf80aff1705ae9c34e7fdd48c1 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Wed, 26 Sep 2018 16:23:08 -0500 Subject: [PATCH 061/118] MAGETWO-95232: Can not create an invoice using Safari - Move jQuery no conflict call to ensure it's executed before prototype is loaded --- app/code/Magento/Theme/view/base/requirejs-config.js | 6 ++++++ lib/web/jquery/patches/jquery.js | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Theme/view/base/requirejs-config.js b/app/code/Magento/Theme/view/base/requirejs-config.js index d6006c21c8a15..52e9270952a95 100644 --- a/app/code/Magento/Theme/view/base/requirejs-config.js +++ b/app/code/Magento/Theme/view/base/requirejs-config.js @@ -64,3 +64,9 @@ var config = { } } }; + +require(['jquery'], function ($) { + 'use strict'; + + $.noConflict(); +}); diff --git a/lib/web/jquery/patches/jquery.js b/lib/web/jquery/patches/jquery.js index 9d733a92159c6..5c741d0832b75 100644 --- a/lib/web/jquery/patches/jquery.js +++ b/lib/web/jquery/patches/jquery.js @@ -22,14 +22,12 @@ define([], function () { return function ($) { var majorVersion = $.fn.jquery.split('.')[0]; - $.noConflict(); - if (majorVersion >= 3) { console.warn('jQuery patch for CVE-2015-9251 is no longer necessary, and should be removed'); } - ajaxResponsePatch(jQuery); + ajaxResponsePatch($); - return jQuery; + return $; }; }); From 33bda6c97d29ff0d3aa4ceb9acfc575ab085aed3 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 27 Sep 2018 11:07:21 -0500 Subject: [PATCH 062/118] MC-4277: Address Product Page slowness due to 'product_data_storage' handling - fix tests --- .../js/product/storage/data-storage.test.js | 9 ++++++--- .../js/product/storage/ids-storage.test.js | 15 ++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/data-storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/data-storage.test.js index fdd0b70997f35..0ab6b5fdf2b99 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/data-storage.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/data-storage.test.js @@ -49,6 +49,7 @@ define([ injector.clean(); injector.remove(); } catch (e) {} + window.localStorage.clear(); }); describe('Magento_Catalog/js/product/storage/data-storage', function () { @@ -88,18 +89,20 @@ define([ }; }); + afterEach(function () { + window.localStorage.clear(); + }); + it('check calls "dataHandler" method with data', function () { var data = { property: 'value' }; obj.dataHandler(data); - expect(obj.localStorage.set).toHaveBeenCalledWith(data); - expect(obj.localStorage.removeAll).not.toHaveBeenCalled(); + expect(window.localStorage.getItem(obj.namespace)).toBe(JSON.stringify(data)); }); it('check calls "dataHandler" method with empty data', function () { obj.dataHandler({}); - expect(obj.localStorage.set).not.toHaveBeenCalled(); expect(obj.localStorage.removeAll).toHaveBeenCalled(); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/ids-storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/ids-storage.test.js index c394a2463f5e2..624b159163bcb 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/ids-storage.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/ids-storage.test.js @@ -27,6 +27,7 @@ define([ injector.clean(); injector.remove(); } catch (e) {} + window.localStorage.clear(); }); describe('Magento_Catalog/js/product/storage/ids-storage', function () { @@ -40,13 +41,6 @@ define([ expect(obj.localStorage.get).toHaveBeenCalled(); }); }); - describe('"cachesDataFromLocalStorage" method', function () { - it('check calls localStorage get method', function () { - obj.getDataFromLocalStorage = jasmine.createSpy().and.returnValue({}); - - expect(obj.localStorage.get).toHaveBeenCalled(); - }); - }); describe('"initLocalStorage" method', function () { it('check returned value', function () { obj.namespace = 'test'; @@ -80,17 +74,16 @@ define([ it('check calls with data that equal with data in localStorage', function () { obj.internalDataHandler(data); - expect(obj.localStorage.get).toHaveBeenCalled(); - expect(obj.localStorage.set).not.toHaveBeenCalled(); + expect(window.localStorage.getItem(obj.namespace)).toBe(JSON.stringify(data)); }); it('check calls with data that not equal with data in localStorage', function () { var emptyData = {}; + obj.internalDataHandler(data); obj.internalDataHandler(emptyData); - expect(obj.localStorage.get).toHaveBeenCalled(); - expect(obj.localStorage.set).toHaveBeenCalledWith(emptyData); + expect(window.localStorage.getItem(obj.namespace)).toBe(JSON.stringify(emptyData)); }); }); describe('"externalDataHandler" method', function () { From b76a01a15360dbd8f5b3c284fd32098d7d298200 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 17 Sep 2018 16:53:28 -0500 Subject: [PATCH 063/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fix functional tests --- ...OrderCancelMassActionPartialFailMessage.php} | 17 +++++++++++++---- .../Test/TestCase/MassOrdersUpdateTest.xml | 12 ++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) rename dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/{AssertOrderCancelMassActionFailMessage.php => AssertOrderCancelMassActionPartialFailMessage.php} (60%) diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php similarity index 60% rename from dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php rename to dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php index fffb0746d4967..6aed5cd39aaad 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php @@ -10,15 +10,20 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Class AssertOrderCancelMassActionFailMessage + * Class AssertOrderCancelAndSuccessMassActionFailMessage * Assert cancel fail message is displayed on order index page */ -class AssertOrderCancelMassActionFailMessage extends AbstractConstraint +class AssertOrderCancelMassActionPartialFailMessage extends AbstractConstraint { + /** + * Message displayed after cancel order from archive + */ + const SUCCESS_MESSAGE = 'We canceled 1 order(s).'; + /** * Text value to be checked */ - const FAIL_CANCEL_MESSAGE = 'You cannot cancel the order(s).'; + const FAIL_CANCEL_MESSAGE = '1 order(s) cannot be canceled.'; /** * Assert cancel fail message is displayed on order index page @@ -32,6 +37,10 @@ public function processAssert(OrderIndex $orderIndex) self::FAIL_CANCEL_MESSAGE, $orderIndex->getMessagesBlock()->getErrorMessage() ); + \PHPUnit\Framework\Assert::assertEquals( + self::SUCCESS_MESSAGE, + $orderIndex->getMessagesBlock()->getSuccessMessage() + ); } /** @@ -41,6 +50,6 @@ public function processAssert(OrderIndex $orderIndex) */ public function toString() { - return 'Cancel fail message is displayed on order index page.'; + return 'Cancel and success fail message is displayed on order index page.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml index e6ab0ff5026b6..31d5c30d25fc7 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml @@ -18,12 +18,12 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation2"> - <data name="description" xsi:type="string">try to cancel orders in status Complete, Closed</data> + <data name="description" xsi:type="string">try to cancel orders in status Complete, Canceled</data> <data name="steps" xsi:type="string">invoice, shipment|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Complete,Processing</data> - <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionFailMessage" /> + <data name="resultStatuses" xsi:type="string">Complete,Canceled</data> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionPartialFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation3"> @@ -31,8 +31,8 @@ <data name="steps" xsi:type="string">invoice|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Processing,Closed</data> - <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionFailMessage" /> + <data name="resultStatuses" xsi:type="string">Processing,Canceled</data> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionPartialFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation4"> @@ -55,7 +55,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation6"> - <data name="description" xsi:type="string">Release order in statuse On Hold</data> + <data name="description" xsi:type="string">Release order in status On Hold</data> <data name="steps" xsi:type="string">on hold</data> <data name="action" xsi:type="string">Unhold</data> <data name="ordersCount" xsi:type="string">1</data> From ed6995c7dfa5d35d57ec4f4df5a39b45b734b3bf Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 27 Sep 2018 16:39:17 -0500 Subject: [PATCH 064/118] MC-4277: Address Product Page slowness due to 'product_data_storage' handling - add localStorage support check --- .../web/js/product/storage/data-storage.js | 17 ++++++++++++++++- .../web/js/product/storage/ids-storage.js | 17 ++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js index 0059cee60d30f..3dc9f3e844516 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/data-storage.js @@ -34,6 +34,21 @@ define([ }; } + /** + * Set data to localStorage with support check. + * + * @param {String} namespace + * @param {Object} data + */ + function setLocalStorageItem(namespace, data) { + try { + window.localStorage.setItem(namespace, JSON.stringify(data)); + } catch (e) { + console.warn('localStorage is unavailable - skipping local caching of product data'); + console.error(e); + } + } + return { /** @@ -118,7 +133,7 @@ define([ if (_.isEmpty(data)) { this.localStorage.removeAll(); } else { - window.localStorage.setItem(this.namespace, JSON.stringify(data)); + setLocalStorageItem(this.namespace, data); } }, diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js index f77bdd0263aa7..ec07c19a2c1b1 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/ids-storage.js @@ -11,6 +11,21 @@ define([ ], function ($, _, ko, utils) { 'use strict'; + /** + * Set data to localStorage with support check. + * + * @param {String} namespace + * @param {Object} data + */ + function setLocalStorageItem(namespace, data) { + try { + window.localStorage.setItem(namespace, JSON.stringify(data)); + } catch (e) { + console.warn('localStorage is unavailable - skipping local caching of product data'); + console.error(e); + } + } + return { /** @@ -94,7 +109,7 @@ define([ * Initializes handler to "data" property update */ internalDataHandler: function (data) { - window.localStorage.setItem(this.namespace, JSON.stringify(data)); + setLocalStorageItem(this.namespace, data); }, /** From 76fd47b8653ff25ebc8f6eee82036364d3d56062 Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Tue, 18 Sep 2018 08:51:47 -0500 Subject: [PATCH 065/118] MAGETWO-94438: AdminAddImageToWYSIWYGProductTest is unstable --- .../Catalog/Test/Mftf/Data/ProductData.xml | 1 + .../Mftf/Section/AdminProductFormSection.xml | 24 ++++---- .../AdminAddImageToWYSIWYGProductTest.xml | 61 ++++++++----------- 3 files changed, 38 insertions(+), 48 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 9ae551b69d388..7c0cc03186c6e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -18,6 +18,7 @@ <data key="urlKey" unique="suffix">testurlkey</data> <data key="status">1</data> <data key="quantity">100</data> + <data key="weight">1</data> <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml index a138c9bbac073..e6ed94e0223bd 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml @@ -105,24 +105,24 @@ <element name="Numlist" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-bullist']" /> <element name="Bullet" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-numlist']" /> <element name="InsertLink" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-link']" /> - <element name="InsertImageIcon" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-image']" /> + <element name="InsertImageIcon" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-image']" timeout="30"/> <element name="InsertTable" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-table']" /> <element name="SpecialCharacter" type="button" selector="//div[@id='editorproduct_form_description']//i[@class='mce-ico mce-i-charmap']" /> - <element name="Browse" type="button" selector=".mce-i-browse"/> - <element name="BrowseUploadImage" type="file" selector=".fileupload" /> + <element name="Browse" type="button" selector=".mce-i-browse" timeout="30"/> + <element name="BrowseUploadImage" type="file" selector=".fileupload" timeout="30"/> <element name="image" type="text" selector="//small[text()='{{var1}}']" parameterized="true"/> <element name="imageSelected" type="text" selector="//small[text()='{{var1}}']/parent::*[@class='filecnt selected']" parameterized="true"/> <element name="ImageSource" type="input" selector=".mce-combobox.mce-abs-layout-item.mce-last.mce-has-open" /> <element name="ImageDescription" type="input" selector=".mce-textbox.mce-abs-layout-item.mce-last" /> <element name="Height" type="input" selector=".mce-textbox.mce-abs-layout-item.mce-first" /> <element name="UploadImage" type="file" selector=".fileupload" /> - <element name="OkBtn" type="button" selector="//span[text()='Ok']"/> + <element name="OkBtn" type="button" selector="//button//span[text()='Ok']"/> <element name="InsertFile" type="text" selector="#insert_files" timeout="30"/> - <element name="CreateFolder" type="button" selector="#new_folder" /> - <element name="DeleteSelectedBtn" type="text" selector="#delete_files"/> - <element name="CancelBtn" type="button" selector="#cancel" /> + <element name="CreateFolder" type="button" selector="#new_folder" timeout="30"/> + <element name="DeleteSelectedBtn" type="text" selector="#delete_files" timeout="30"/> + <element name="CancelBtn" type="button" selector=".page-actions #cancel" /> <element name="FolderName" type="button" selector="input[data-role='promptField']" /> - <element name="AcceptFolderName" type="button" selector=".action-primary.action-accept" /> + <element name="AcceptFolderName" type="button" selector=".action-primary.action-accept" timeout="30"/> <element name="StorageRootArrow" type="button" selector="#root > .jstree-icon" /> <element name="checkIfArrowExpand" type="button" selector="//li[@id='root' and contains(@class,'jstree-closed')]" /> <element name="WysiwygArrow" type="button" selector="#d3lzaXd5Zw-- > .jstree-icon" /> @@ -143,21 +143,21 @@ <element name="Numlist" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-bullist']" /> <element name="Bullet" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-numlist']" /> <element name="InsertLink" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-link']" /> - <element name="InsertImageIcon" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-image']" /> + <element name="InsertImageIcon" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-image']" timeout="30"/> <element name="InsertTable" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-table']" /> <element name="SpecialCharacter" type="button" selector="//div[@id='editorproduct_form_short_description']//i[@class='mce-ico mce-i-charmap']"/> <element name="Browse" type="button" selector=".mce-i-browse"/> - <element name="BrowseUploadImage" type="file" selector=".fileupload" /> + <element name="BrowseUploadImage" type="file" selector=".fileupload" timeout="30" /> <element name="image" type="text" selector="//small[text()='{{var1}}']" parameterized="true"/> <element name="imageSelected" type="text" selector="//small[text()='{{var1}}']/parent::*[@class='filecnt selected']" parameterized="true"/> <element name="ImageSource" type="input" selector=".mce-combobox.mce-abs-layout-item.mce-last.mce-has-open" /> <element name="ImageDescription" type="input" selector=".mce-textbox.mce-abs-layout-item.mce-last" /> <element name="Height" type="input" selector=".mce-textbox.mce-abs-layout-item.mce-first" /> <element name="UploadImage" type="file" selector=".fileupload" /> - <element name="OkBtn" type="button" selector="//span[text()='Ok']"/> + <element name="OkBtn" type="button" selector="//span[text()='Ok']" timeout="30"/> <element name="InsertFile" type="text" selector="#insert_files"/> <element name="CreateFolder" type="button" selector="#new_folder" /> - <element name="DeleteSelectedBtn" type="text" selector="#delete_files"/> + <element name="DeleteSelectedBtn" type="text" selector="#delete_files" timeout="30"/> <element name="CancelBtn" type="button" selector="#cancel" /> <element name="FolderName" type="button" selector="input[data-role='promptField']" /> <element name="AcceptFolderName" type="button" selector=".action-primary.action-accept" /> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml index bd1c057133d83..37c0eb6ea1253 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml @@ -16,82 +16,75 @@ <description value="Admin should be able to add image to WYSIWYG Editor on Product Page"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84375"/> - <skip> - <issueId value="MAGETWO-94438"/> - </skip> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYG" stepKey="enableWYSIWYG"/> <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> </before> + <after> + <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <amOnPage url="{{AdminProductCreatePage.url(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToNewProduct"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <fillField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> - <fillField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> - <fillField userInput="{{_defaultProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> - <fillField userInput="{{_defaultProduct.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> - <scrollTo selector="{{AdminProductFormSection.productQuantity}}" stepKey="scrollToQty" /> + <waitForPageLoad stepKey="waitForPageLoadProductCreatePage"/> + <actionGroup ref="fillMainProductForm" stepKey="fillBasicProductInfo" /> + <click selector="{{AdminProductFormSection.contentTab}}" stepKey="clickContentTab" /> <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.TinyMCE4}}" stepKey="waitForDescription" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertImageIcon}}" stepKey="clickInsertImageIcon1" /> - <waitForPageLoad stepKey="waitForPageLoad1" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.Browse}}" stepKey="clickBrowse1" /> - <waitForPageLoad stepKey="waitForPageLoad2" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> + <waitForLoadingMaskToDisappear stepKey="waitForBrowseModal" /> <see selector="{{ProductDescriptionWYSIWYGToolbarSection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn1" /> <see selector="{{ProductDescriptionWYSIWYGToolbarSection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn1" /> - <click selector="{{ProductDescriptionWYSIWYGToolbarSection.CreateFolder}}" stepKey="createFolder1"/> - <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.FolderName}}" stepKey="waitForPopUp1" /> + <dontSeeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="dontSeeAddSelectedBtn1" /> + <click selector="{{ProductDescriptionWYSIWYGToolbarSection.CreateFolder}}" stepKey="createFolder1" /> + <waitForElement selector="{{ProductDescriptionWYSIWYGToolbarSection.FolderName}}" stepKey="waitForPopUp1" /> <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.FolderName}}" userInput="{{ImageFolder.name}}" stepKey="fillFolderName1" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.AcceptFolderName}}" stepKey="acceptFolderName11" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> <conditionalClick selector="{{ProductDescriptionWYSIWYGToolbarSection.StorageRootArrow}}" dependentSelector="{{ProductDescriptionWYSIWYGToolbarSection.checkIfArrowExpand}}" stepKey="clickStorageRootArrowIfClosed" visible="true"/> <conditionalClick selector="{{ProductDescriptionWYSIWYGToolbarSection.WysiwygArrow}}" dependentSelector="{{ProductDescriptionWYSIWYGToolbarSection.checkIfWysiwygArrowExpand}}" stepKey="clickWysiwygArrowIfClosed" visible="true"/> <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder1" /> <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder1" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading4" /> <attachFile selector="{{ProductDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload1.value}}" stepKey="uploadImage1"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> + <waitForLoadingMaskToDisappear stepKey="waitForFileUpload1" /> <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="waitForUploadImage1" /> <seeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.imageSelected(ImageUpload1.value)}}" stepKey="seeImageSelected1" /> <see selector="{{ProductDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn1"/> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected1" /> - <waitForText userInput="OK" stepKey="waitForConfirm1" /> - <click selector="{{ProductDescriptionWYSIWYGToolbarSection.confirmDelete}}" stepKey="confirmDelete1" /> + <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitForConfirmDelete1"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDelete1" /> <waitForElementNotVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="waitForImageDeleted1" /> <dontSeeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="dontSeeImage1" /> + <dontSeeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="dontSeeAddSelectedBtn2" /> <attachFile selector="{{ProductDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload1.value}}" stepKey="uploadImage2"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> + <waitForLoadingMaskToDisappear stepKey="waitForFileUpload2" /> <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="waitForUploadImage2" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="clickInsertBtn1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading7" /> - <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.OkBtn}}" stepKey="waitForOkBtn1" /> + <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.ImageDescription}}" stepKey="waitForImageDescriptionButton1" /> <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.ImageDescription}}" userInput="{{ImageUpload1.content}}" stepKey="fillImageDescription1" /> <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.Height}}" userInput="{{ImageUpload1.height}}" stepKey="fillImageHeight1" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.OkBtn}}" stepKey="clickOkBtn1" /> - <waitForPageLoad stepKey="waitForPageLoad3"/> <scrollTo selector="{{ProductDescriptionWYSIWYGToolbarSection.TinyMCE4}}" stepKey="scrollToTinyMCE4" /> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.InsertImageIcon}}" stepKey="clickInsertImageIcon2" /> - <waitForPageLoad stepKey="waitForPageLoad4" /> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.Browse}}" stepKey="clickBrowse2" /> - <waitForPageLoad stepKey="waitForPageLoad5" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading8" /> + <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.CancelBtn}}" stepKey="waitForCancelButton2"/> <see selector="{{ProductShortDescriptionWYSIWYGToolbarSection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn2" /> <see selector="{{ProductShortDescriptionWYSIWYGToolbarSection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn2" /> - <dontSeeElement selector="{{ProductShortDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="dontSeeAddSelectedBtn2" /> + <dontSeeElement selector="{{ProductShortDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="dontSeeAddSelectedBtn3" /> <attachFile selector="{{ProductShortDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload3.value}}" stepKey="uploadImage3"/> + <waitForLoadingMaskToDisappear stepKey="waitForFileUpload3" /> <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.image(ImageUpload3.value)}}" stepKey="waitForUploadImage3" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading9" /> - <wait time="3" stepKey="waitMore" /> <waitForElement selector="{{ProductShortDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" stepKey="waitForDeletebtn" /> <see selector="{{ProductShortDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn2"/> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected2" /> - <waitForText userInput="OK" stepKey="waitForConfirm3" /> - <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.confirmDelete}}" stepKey="confirmDelete2" /> + <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitForConfirm3"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDelete2" /> + <dontSeeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="dontSeeAddSelectedBtn4" /> <attachFile selector="{{ProductShortDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload3.value}}" stepKey="uploadImage4"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading10" /> + <waitForLoadingMaskToDisappear stepKey="waitForFileUpload4" /> <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.image(ImageUpload3.value)}}" stepKey="waitForUploadImage4" /> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="clickInsertBtn" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading11" /> @@ -107,9 +100,5 @@ <seeElement selector="{{StorefrontProductInfoMainSection.mediaDescription}}" stepKey="assertMediaDescription"/> <seeElementInDOM selector="{{StorefrontCategoryMainSection.imageSource(ImageUpload3.fileName)}}" stepKey="assertMediaSource3"/> <seeElementInDOM selector="{{StorefrontCategoryMainSection.imageSource(ImageUpload1.fileName)}}" stepKey="assertMediaSource1"/> - <after> - <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> - <actionGroup ref="logout" stepKey="logout"/> - </after> </test> </tests> From c4c8af6b221a84e5f389a95a29bc60af4fc3ae44 Mon Sep 17 00:00:00 2001 From: roman <rleshchenko@magento.com> Date: Fri, 28 Sep 2018 18:27:01 +0300 Subject: [PATCH 066/118] MAGETWO-70943: Incorrect reset password flow --- app/code/Magento/Customer/Model/AccountManagement.php | 4 ++-- .../view/frontend/email/password_reset_confirmation.html | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 6aee2894f4907..06c1f41c3888c 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -661,7 +661,7 @@ private function handleUnknownTemplate($template) /** * @inheritdoc */ - public function resetPassword($email, $resetToken, $newPassword): bool + public function resetPassword($email, $resetToken, $newPassword) { if (!$email) { $customer = $this->matchCustomerByRpToken($resetToken); @@ -1093,7 +1093,7 @@ public function isCustomerInStore($customerWebsiteId, $storeId) * @throws \Magento\Framework\Exception\NoSuchEntityException If customer doesn't exist * @throws LocalizedException */ - private function validateResetPasswordToken(?int $customerId, ?string $resetPasswordLinkToken) : bool + private function validateResetPasswordToken($customerId, $resetPasswordLinkToken) { if ($customerId !== null && $customerId <= 0) { throw new InputException( diff --git a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html index f33350ea48241..59e7f16adfd51 100644 --- a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html +++ b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html @@ -22,7 +22,6 @@ <tr> <td align="center"> <a href="{{var this.getUrl($store,'customer/account/createPassword/',[_query:[token:$customer.rp_token],_nosid:1])}}" target="_blank">{{trans "Set a New Password"}}</a> - </td> </tr> </table> From 956f36132e3438acfea61a3e4cd41b43e1bd1fc0 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Fri, 28 Sep 2018 12:01:29 -0500 Subject: [PATCH 067/118] MAGETWO-95048: Sidebar navigation is broken for Stores > Configuration, All Stores. - Pass frontname to getSecretKey if route not found - Add MFTF test to cover this fix --- app/code/Magento/Backend/Block/Menu.php | 4 +- .../Test/Mftf/Section/AdminMenuSection.xml | 3 +- .../AdminMenuNavigationWithSecretKeysTest.xml | 50 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Backend/Test/Mftf/Test/AdminMenuNavigationWithSecretKeysTest.xml diff --git a/app/code/Magento/Backend/Block/Menu.php b/app/code/Magento/Backend/Block/Menu.php index 744c4d06a0d17..3ef4168238b48 100644 --- a/app/code/Magento/Backend/Block/Menu.php +++ b/app/code/Magento/Backend/Block/Menu.php @@ -75,7 +75,7 @@ class Menu extends \Magento\Backend\Block\Template private $anchorRenderer; /** - * @var ConfigInterface + * @var \Magento\Framework\App\Route\ConfigInterface */ private $routeConfig; @@ -216,7 +216,7 @@ protected function _callbackSecretKey($match) { $routeId = $this->routeConfig->getRouteByFrontName($match[1]); return \Magento\Backend\Model\UrlInterface::SECRET_KEY_PARAM_NAME . '/' . $this->_url->getSecretKey( - $routeId, + $routeId ?: $match[1], $match[2], $match[3] ); diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml index 9d3182b6236a4..9e4a6d9219526 100644 --- a/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml +++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml @@ -7,9 +7,10 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminMenuSection"> <element name="catalog" type="button" selector="#menu-magento-catalog-catalog"/> + <element name="catalogProducts" type="button" selector="#nav li[data-ui-id='menu-magento-catalog-catalog-products']"/> <element name="customers" type="button" selector="#menu-magento-customer-customer"/> <element name="content" type="button" selector="#menu-magento-backend-content"/> <element name="widgets" type="button" selector="#nav li[data-ui-id='menu-magento-widget-cms-widget-instance']"/> diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminMenuNavigationWithSecretKeysTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminMenuNavigationWithSecretKeysTest.xml new file mode 100644 index 0000000000000..c9a3b8089cc1d --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminMenuNavigationWithSecretKeysTest.xml @@ -0,0 +1,50 @@ +<?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="AdminMenuNavigationWithSecretKeysTest"> + <annotations> + <features value="Backend"/> + <stories value="Menu Navigation"/> + <title value="Admin should be able to navigate between menu options with secret url keys enabled"/> + <description value="Admin should be able to navigate between menu options with secret url keys enabled"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-95349"/> + <group value="menu"/> + </annotations> + <before> + <magentoCLI command="config:set admin/security/use_form_key 1" stepKey="enableUrlSecretKeys"/> + <magentoCLI command="cache:clean config full_page" stepKey="cleanInvalidatedCaches1"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <magentoCLI command="config:set admin/security/use_form_key 0" stepKey="disableUrlSecretKeys"/> + <magentoCLI command="cache:clean config full_page" stepKey="cleanInvalidatedCaches2"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <click selector="{{AdminMenuSection.stores}}" stepKey="clickStoresMenuOption1"/> + <waitForLoadingMaskToDisappear stepKey="waitForStoresMenu1" /> + <click selector="{{AdminMenuSection.configuration}}" stepKey="clickStoresConfigurationMenuOption1"/> + <waitForPageLoad stepKey="waitForConfigurationPageLoad1"/> + <seeCurrentUrlMatches regex="~\/admin\/system_config\/~" stepKey="seeCurrentUrlMatchesConfigPath1"/> + + <click selector="{{AdminMenuSection.catalog}}" stepKey="clickCatalogMenuOption"/> + <waitForLoadingMaskToDisappear stepKey="waitForCatalogMenu1" /> + <click selector="{{AdminMenuSection.catalogProducts}}" stepKey="clickCatalogProductsMenuOption"/> + <waitForPageLoad stepKey="waitForProductsPageLoad"/> + <seeCurrentUrlMatches regex="~\/catalog\/product\/~" stepKey="seeCurrentUrlMatchesProductsPath"/> + + <click selector="{{AdminMenuSection.stores}}" stepKey="clickStoresMenuOption2"/> + <waitForLoadingMaskToDisappear stepKey="waitForStoresMenu2" /> + <click selector="{{AdminMenuSection.configuration}}" stepKey="clickStoresConfigurationMenuOption2"/> + <waitForPageLoad stepKey="waitForConfigurationPageLoad2"/> + <seeCurrentUrlMatches regex="~\/admin\/system_config\/~" stepKey="seeCurrentUrlMatchesConfigPath2"/> + </test> +</tests> From 50da0a7fde2b207ecf78c768586db51e70d96898 Mon Sep 17 00:00:00 2001 From: Tommy Wiebell <twiebell@adobe.com> Date: Fri, 28 Sep 2018 14:49:53 -0500 Subject: [PATCH 068/118] MAGETWO-95048: Sidebar navigation is broken for Stores > Configuration, All Stores. - Fix up docblocks causing code sniff errors --- app/code/Magento/Backend/Block/Menu.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Backend/Block/Menu.php b/app/code/Magento/Backend/Block/Menu.php index 3ef4168238b48..1e2561e2efe05 100644 --- a/app/code/Magento/Backend/Block/Menu.php +++ b/app/code/Magento/Backend/Block/Menu.php @@ -9,12 +9,12 @@ /** * Backend menu block * - * @api - * @method \Magento\Backend\Block\Menu setAdditionalCacheKeyInfo(array $cacheKeyInfo) + * @method $this setAdditionalCacheKeyInfo(array $cacheKeyInfo) * @method array getAdditionalCacheKeyInfo() - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @api * @since 100.0.2 + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Menu extends \Magento\Backend\Block\Template { @@ -80,16 +80,17 @@ class Menu extends \Magento\Backend\Block\Template private $routeConfig; /** - * @param Template\Context $context + * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Backend\Model\UrlInterface $url * @param \Magento\Backend\Model\Menu\Filter\IteratorFactory $iteratorFactory * @param \Magento\Backend\Model\Auth\Session $authSession * @param \Magento\Backend\Model\Menu\Config $menuConfig * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param \Magento\Framework\App\Route\ConfigInterface $routeConfig * @param array $data * @param MenuItemChecker|null $menuItemChecker * @param AnchorRenderer|null $anchorRenderer + * @param \Magento\Framework\App\Route\ConfigInterface|null $routeConfig + * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -141,6 +142,7 @@ protected function _getAnchorLabel($menuItem) /** * Render menu item mouse events + * * @param \Magento\Backend\Model\Menu\Item $menuItem * @return string */ @@ -354,7 +356,7 @@ protected function _columnBrake($items, $limit) * @param \Magento\Backend\Model\Menu\Item $menuItem * @param int $level * @param int $limit - * @param $id int + * @param int|null $id * @return string HTML code */ protected function _addSubMenu($menuItem, $level, $limit, $id = null) From 706fd1b965e1a04a6f7109b3300b24bddeccb19c Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@adobe.com> Date: Fri, 28 Sep 2018 17:03:01 -0500 Subject: [PATCH 069/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - updated test --- .../Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 3fdbb3eae0b19..66316d0af8b60 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -64,6 +64,7 @@ <!--Submit Order and verify information--> <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder" after="seeCorrectGrandTotal"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskTodisappear"/> <waitForPageLoad stepKey="waitForOrderToProcess"/> <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPage" after="clickSubmitOrder"/> <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeSuccessMessage" after="seeViewOrderPage"/> @@ -122,7 +123,8 @@ <!--Update Qty of items to be refunded and submit refund--> <scrollTo selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" stepKey="scrollToItemsToRefund"/> <fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" stepKey="fillQtyOfItemsToRefund" after="scrollToItemsToRefund"/> - <click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/> + + <!--<click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/>--> <waitForLoadingMaskToDisappear stepKey="waitForRefundQtyToUpdate"/> <waitForElementVisible selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="seeSubmitRefundBtn"/> <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="submitRefundOffline"/> From e9a4403f89a67818e694fbe0c0d0233b36ec8c4b Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 19 Sep 2018 11:05:57 -0500 Subject: [PATCH 070/118] MQE-1139: cleanup test modules in dev/tests/acceptance --- .../Mftf}/Metadata/image_content-meta.xml | 0 .../Test/StoreFrontMobileViewValidation.xml | 1 + .../Test/StorefrontRedirectToOrderHistory.xml | 1 + .../FunctionalTest/Framework/LICENSE.txt | 48 --- .../FunctionalTest/Framework/LICENSE_AFL.txt | 48 --- .../FunctionalTest/Framework/README.md | 3 - .../ActionGroup/TemplateActionGroupFile.xml | 14 - .../SampleTemplates/Data/TemplateDataFile.xml | 14 - .../SampleTemplates/LICENSE.txt | 48 --- .../SampleTemplates/LICENSE_AFL.txt | 48 --- .../Metadata/TemplateMetaFile.xml | 22 -- .../SampleTemplates/Page/TemplatePageFile.xml | 14 - .../FunctionalTest/SampleTemplates/README.md | 3 - .../Section/TemplateSectionFile.xml | 14 - .../SampleTemplates/Test/TemplateTestFile.xml | 24 -- .../ActionGroup/SampleActionGroup.xml | 24 -- .../SampleTests/Data/SampleData.xml | 32 -- .../FunctionalTest/SampleTests/LICENSE.txt | 48 --- .../SampleTests/LICENSE_AFL.txt | 48 --- .../SampleTests/Page/SamplePage.xml | 14 - .../FunctionalTest/SampleTests/README.md | 3 - .../SampleTests/Section/SampleSection.xml | 20 -- .../SampleTests/Test/AdvancedSampleTest.xml | 54 ---- .../SampleTests/Test/AssertsTest.xml | 79 ----- .../CreateConfigurableProductByApiTest.xml | 77 ----- .../Test/CreateSalesRuleByApiTest.xml | 24 -- .../SampleTests/Test/MinimumTest.xml | 26 -- .../Test/PersistMultipleEntitiesTest.xml | 36 --- .../SampleTests/Test/SampleTest.xml | 298 ------------------ .../Test/SetPaymentConfigurationTest.xml | 31 -- .../Test/UpdateSimpleProductByApiTest.xml | 29 -- 31 files changed, 2 insertions(+), 1143 deletions(-) rename {dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework => app/code/Magento/Catalog/Test/Mftf}/Metadata/image_content-meta.xml (100%) delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/ActionGroup/TemplateActionGroupFile.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Data/TemplateDataFile.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE.txt delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE_AFL.txt delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Metadata/TemplateMetaFile.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Page/TemplatePageFile.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/README.md delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Section/TemplateSectionFile.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Test/TemplateTestFile.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/ActionGroup/SampleActionGroup.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Data/SampleData.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE.txt delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE_AFL.txt delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Page/SamplePage.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/README.md delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Section/SampleSection.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/MinimumTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SampleTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml delete mode 100644 dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/Metadata/image_content-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/image_content-meta.xml similarity index 100% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/Metadata/image_content-meta.xml rename to app/code/Magento/Catalog/Test/Mftf/Metadata/image_content-meta.xml diff --git a/app/code/Magento/Cms/Test/Mftf/Test/StoreFrontMobileViewValidation.xml b/app/code/Magento/Cms/Test/Mftf/Test/StoreFrontMobileViewValidation.xml index d1c44383b4ac1..6165def067ef4 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/StoreFrontMobileViewValidation.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/StoreFrontMobileViewValidation.xml @@ -11,6 +11,7 @@ <test name="StoreFrontMobileViewValidation"> <annotations> <features value="Cms"/> + <stories value="Mobile view page footer should stick to the bottom of page on Store front"/> <title value="Mobile view page footer should stick to the bottom of page on Store front"/> <description value="Mobile view page footer should stick to the bottom of page on Store front"/> <severity value="MAJOR"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontRedirectToOrderHistory.xml b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontRedirectToOrderHistory.xml index ec725ad5fe4c5..19bcca985f974 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontRedirectToOrderHistory.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontRedirectToOrderHistory.xml @@ -11,6 +11,7 @@ <test name="StorefrontRedirectToOrderHistory"> <annotations> <features value="Redirection Rules"/> + <stories value="Create Invoice"/> <title value="Create Invoice"/> <description value="Check while order printing URL with an id of not relevant order redirects to order history"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt deleted file mode 100644 index 49525fd99da9c..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Open Software License ("OSL") v. 3.0 - -This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Open Software License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt deleted file mode 100644 index f39d641b18a19..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Academic Free License ("AFL") v. 3.0 - -This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Academic Free License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md deleted file mode 100644 index 7fbe454f709c2..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Magento 2 Functional Tests - -The Functional Tests Module for **Magento_Framework**. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/ActionGroup/TemplateActionGroupFile.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/ActionGroup/TemplateActionGroupFile.xml deleted file mode 100644 index d1bc251f26321..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/ActionGroup/TemplateActionGroupFile.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name=""> - <!-- ADD TEST STEPS HERE --> - </actionGroup> -</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Data/TemplateDataFile.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Data/TemplateDataFile.xml deleted file mode 100644 index 6f13f04aef31d..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Data/TemplateDataFile.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="" type=""> - <data key=""></data> - </entity> -</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE.txt deleted file mode 100644 index 49525fd99da9c..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Open Software License ("OSL") v. 3.0 - -This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Open Software License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE_AFL.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE_AFL.txt deleted file mode 100644 index f39d641b18a19..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/LICENSE_AFL.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Academic Free License ("AFL") v. 3.0 - -This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Academic Free License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Metadata/TemplateMetaFile.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Metadata/TemplateMetaFile.xml deleted file mode 100644 index 7293cea9a9b83..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Metadata/TemplateMetaFile.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> - <operation name="" dataType="" type="" auth="adminOauth" url="" method=""> - <contentType>application/json</contentType> - <param key=""></param> - <object dataType="" key=""> - <field key=""></field> - <array key=""> - <value></value> - </array> - </object> - <field key=""></field> - </operation> -</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Page/TemplatePageFile.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Page/TemplatePageFile.xml deleted file mode 100644 index 27559a48bef06..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Page/TemplatePageFile.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="" url="" area="" module=""> - <section name=""/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/README.md deleted file mode 100644 index 986c2af6164e9..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Magento 2 Functional Tests - -The Functional Tests Module for **Magento_SampleTemplates** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Section/TemplateSectionFile.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Section/TemplateSectionFile.xml deleted file mode 100644 index 4c1cd7300cf2f..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Section/TemplateSectionFile.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name=""> - <element name="" type="" selector=""/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Test/TemplateTestFile.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Test/TemplateTestFile.xml deleted file mode 100644 index d9a98d4baa6cb..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/Test/TemplateTestFile.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="TemplateTestFile"> - <annotations> - <features value=""/> - <stories value=""/> - </annotations> - <before> - - </before> - <after> - - </after> - <!-- ADD TEST STEPS HERE --> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/ActionGroup/SampleActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/ActionGroup/SampleActionGroup.xml deleted file mode 100644 index 45ec5f3adf218..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/ActionGroup/SampleActionGroup.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="SampleActionGroup"> - <arguments> - <argument name="person" defaultValue="SamplePerson"/> - </arguments> - <fillField selector="#foo" userInput="{{person.foo}}" stepKey="fillField1"/> - <fillField selector="#bar" userInput="{{person.bar}}" stepKey="fillField2"/> - </actionGroup> - <actionGroup name="ValidateSlideOutPanelField"> - <arguments> - <argument name="property" defaultValue=""/> - </arguments> - <see userInput="{{property.name}}" selector="{{ColumnSection.panelFieldLabel(property.section, property.fieldName, property.section, property.name)}}" stepKey="seePropertyLabel"/> - </actionGroup> -</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Data/SampleData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Data/SampleData.xml deleted file mode 100644 index 361f06a6ff333..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Data/SampleData.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="SamplePerson" type="samplePerson"> - <data key="foo">foo</data> - <data key="bar">bar</data> - <data key="lastName">Doe</data> - <data key="email" unique="prefix">.email@gmail.com</data> - </entity> - <entity name="OverrideDefaultPerson" type="samplePerson"> - <data key="foo">fizz</data> - <data key="bar">buzz</data> - </entity> - <entity name="AppearanceMinHeightProperty" type="min_height_property"> - <data key="name">Minimum Height</data> - <data key="section">appearance</data> - <data key="fieldName">min_height</data> - </entity> - <entity name="AssertThis" type="samplePerson"> - <data key="firstname">Well</data> - <data key="lastname">Done</data> - <data key="email" unique="prefix">.email@gmail.com</data> - </entity> -</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE.txt deleted file mode 100644 index 49525fd99da9c..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Open Software License ("OSL") v. 3.0 - -This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Open Software License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE_AFL.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE_AFL.txt deleted file mode 100644 index f39d641b18a19..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/LICENSE_AFL.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Academic Free License ("AFL") v. 3.0 - -This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Academic Free License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Page/SamplePage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Page/SamplePage.xml deleted file mode 100644 index 6fd2a54c6014e..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Page/SamplePage.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="SamplePage" url="/{{var1}}/{{var2}}.html" area="storefront" module="SampleTests" parameterized="true"> - <section name="SampleSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/README.md deleted file mode 100644 index f3340b205f1a3..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Magento 2 Functional Tests - -The Functional Tests Module for **Magento_SampleTests** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Section/SampleSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Section/SampleSection.xml deleted file mode 100644 index 6aa54d2fb9b83..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Section/SampleSection.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="SampleSection"> - <element name="oneParamElement" type="button" selector="#element .{{var1}}" parameterized="true"/> - <element name="twoParamElement" type="button" selector="#{{var1}} .{{var2}}" parameterized="true"/> - <element name="threeParamElement" type="button" selector="#{{var1}}-{{var2}} .{{var3}}" parameterized="true"/> - <element name="timeoutElement" type="button" selector="#foo" timeout="30"/> - </section> - <section name="ColumnSection"> - <element name="panelFieldLabel" type="text" selector='//div[@data-index="{{arg1}}"]/descendant::div[@data-index="{{arg2}}"]/label | //div[@data-index="{{arg3}}"]/descendant::*[@class="admin__field-label"]/span[text()="{{arg4}}"]' parameterized="true" /> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml deleted file mode 100644 index 4fead0e51497e..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdvancedSampleTest"> - <annotations> - <features value="SampleTests"/> - <title value=""/> - <description value=""/> - <severity value="CRITICAL"/> - <testCaseId value="#"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <before> - <createData entity="SamplePerson" stepKey="beforeData"/> - </before> - <after> - - </after> - - <!-- Create an entity that depends on another entity --> - <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="_defaultProduct" stepKey="createProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - - <!-- Parameterized url --> - <amOnPage url="{{SamplePage.url('foo', SamplePerson.bar)}}" stepKey="amOnPage"/> - - <!-- Parameterized selector --> - <grabTextFrom selector="{{SampleSection.twoParamElement(SamplePerson.foo, 'bar')}}" stepKey="grabTextFrom"/> - - <!-- Element with a timeout --> - <click selector="{{SampleSection.timeoutElement}}" stepKey="click"/> - - <!-- ActionGroup --> - <actionGroup ref="SampleActionGroup" stepKey="actionGroup"> - <argument name="person" value="OverrideDefaultPerson"/> - </actionGroup> - - <actionGroup ref="ValidateSlideOutPanelField" stepKey="seeAppearanceMinHeightProperty"> - <argument name="property" value="AppearanceMinHeightProperty"/> - </actionGroup> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml deleted file mode 100644 index 200c52cab797d..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml +++ /dev/null @@ -1,79 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- Test XML Example --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AssertsTest"> - <annotations> - <features value="SampleTests"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - - <createData entity="Simple_US_Customer" stepKey="createData2"/> - <amOnUrl url="https://www.yahoo.com" stepKey="amOnPage"/> - <waitForElementVisible stepKey="wait1" selector="#uh-logo" time="10"/> - <grabTextFrom selector="#uh-logo" stepKey="grabTextFrom1"/> - - <!-- asserts without variable replacement --> - <assertArrayHasKey stepKey="assertArrayHasKey" message="pass"> - <expectedResult type="string">apple</expectedResult> - <actualResult type="const">['orange' => 2, 'apple' => 1]</actualResult> - </assertArrayHasKey> - <assertEquals stepKey="assertEquals1" message="pass"> - <expectedResult type="variable">grabTextFrom1</expectedResult> - <actualResult type="string">Copyright © 2013-2017 Magento, Inc. All rights reserved.</actualResult> - </assertEquals> - <assertFalse stepKey="assertFalse1" message="pass"> - <actualResult type="bool">0</actualResult> - </assertFalse> - <assertGreaterOrEquals stepKey="assertGreaterOrEquals" message="pass"> - <expectedResult type="int">2</expectedResult> - <actualResult type="int">5</actualResult> - </assertGreaterOrEquals> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute1" selector="#username" attribute="class"> - <expectedResult type="string">admin__control-text</expectedResult> - </assertElementContainsAttribute> - - <!-- string type that use created data --> - <assertStringStartsWith stepKey="assert1" message="fail"> - <expectedResult type="string">D</expectedResult> - <actualResult type="string">$$createData1.lastname$$, $$createData1.firstname$$</actualResult> - </assertStringStartsWith> - <assertStringStartsNotWith stepKey="assert2" message="pass"> - <expectedResult type="string">W</expectedResult> - <actualResult type="string">$createData2.firstname$, $createData2.lastname$</actualResult> - </assertStringStartsNotWith> - <assertEquals stepKey="assert5" message="pass"> - <expectedResult type="string">$$createData1.lastname$$</expectedResult> - <actualResult type="string">$$createData1.lastname$$</actualResult> - </assertEquals> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute7" selector="#username" attribute="value"> - <expectedResult type="const">$createData2.firstname$</expectedResult> - </assertElementContainsAttribute> - - <!-- array type that use created data --> - <assertArraySubset stepKey="assert9" message="pass"> - <expectedResult type="array">[$$createData1.lastname$$, $$createData1.firstname$$]</expectedResult> - <actualResult type="array">[$$createData1.lastname$$, $$createData1.firstname$$, 1]</actualResult> - </assertArraySubset> - <assertArraySubset stepKey="assert10" message="pass"> - <expectedResult type="array">[$createData2.firstname$, $createData2.lastname$]</expectedResult> - <actualResult type="array">[$createData2.firstname$, $createData2.lastname$, 1]</actualResult> - </assertArraySubset> - <assertArrayHasKey stepKey="assert3" message="pass"> - <expectedResult type="string">lastname</expectedResult> - <actualResult type="array">['lastname' => $$createData1.lastname$$, 'firstname' => $$createData1.firstname$$]</actualResult> - </assertArrayHasKey> - <assertArrayHasKey stepKey="assert4" message="pass"> - <expectedResult type="string">lastname</expectedResult> - <actualResult type="array">['lastname' => $createData2.lastname$, 'firstname' => $createData2.firstname$]</actualResult> - </assertArrayHasKey> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml deleted file mode 100644 index d759d1ab27498..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml +++ /dev/null @@ -1,77 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="CreateConfigurableProductByApiTest"> - <annotations> - <features value="SampleTests"/> - <stories value="Create a Configurable Product By API"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <before> - <createData stepKey="categoryHandle" entity="SimpleSubCategory" /> - <createData stepKey="baseConfigProductHandle" entity="BaseConfigurableProduct" > - <requiredEntity createDataKey="categoryHandle"/> - </createData> - <createData stepKey="productAttributeHandle" entity="productDropDownAttribute"/> - - <createData stepKey="productAttributeOption1Handle" entity="productAttributeOption1"> - <requiredEntity createDataKey="productAttributeHandle"/> - </createData> - <createData stepKey="productAttributeOption2Handle" entity="productAttributeOption2"> - <requiredEntity createDataKey="productAttributeHandle"/> - </createData> - - <createData stepKey="addToAttributeSetHandle" entity="AddToDefaultSet"> - <requiredEntity createDataKey="productAttributeHandle"/> - </createData> - - <getData stepKey="getAttributeOption1Handle" entity="ProductAttributeOptionGetter" index="1"> - <requiredEntity createDataKey="productAttributeHandle"/> - </getData> - <getData stepKey="getAttributeOption2Handle" entity="ProductAttributeOptionGetter" index="2"> - <requiredEntity createDataKey="productAttributeHandle"/> - </getData> - - <createData stepKey="childProductHandle1" entity="SimpleOne"> - <requiredEntity createDataKey="productAttributeHandle"/> - <requiredEntity createDataKey="getAttributeOption1Handle"/> - </createData> - <createData stepKey="childProductHandle2" entity="SimpleOne"> - <requiredEntity createDataKey="productAttributeHandle"/> - <requiredEntity createDataKey="getAttributeOption2Handle"/> - </createData> - - <createData stepKey="configProductOptionHandle" entity="ConfigurableProductTwoOptions"> - <requiredEntity createDataKey="baseConfigProductHandle"/> - <requiredEntity createDataKey="productAttributeHandle"/> - <requiredEntity createDataKey="getAttributeOption1Handle"/> - <requiredEntity createDataKey="getAttributeOption2Handle"/> - </createData> - - <createData stepKey="configProductHandle1" entity="ConfigurableProductAddChild"> - <requiredEntity createDataKey="childProductHandle1"/> - <requiredEntity createDataKey="baseConfigProductHandle"/> - </createData> - <createData stepKey="configProductHandle2" entity="ConfigurableProductAddChild"> - <requiredEntity createDataKey="childProductHandle2"/> - <requiredEntity createDataKey="baseConfigProductHandle"/> - </createData> - </before> - <after> - <deleteData stepKey="d2" createDataKey="childProductHandle1"/> - <deleteData stepKey="d3" createDataKey="childProductHandle2"/> - <deleteData stepKey="d7" createDataKey="baseConfigProductHandle"/> - <deleteData stepKey="d8" createDataKey="categoryHandle"/> - <deleteData stepKey="d6" createDataKey="productAttributeHandle"/> - </after> - </test> -</tests> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml deleted file mode 100644 index 8cd83fd62067f..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="CreateSalesRuleByApiTest"> - <annotations> - <features value="SampleTests"/> - <stories value="Create a Sales Rule By API"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <before> - <createData stepKey="saleRule" entity="SimpleSalesRule" /> - </before> - <!--see stepKey="test" userInput="$$saleRule.store_labels[0][store_id]$$" selector="test"/--> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/MinimumTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/MinimumTest.xml deleted file mode 100644 index f8702eeaf5e0c..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/MinimumTest.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- Test XML Example --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="MinimumTest"> - <annotations> - <features value="SampleTests"/> - <title value="Minimum Test"/> - <description value="Minimum Test"/> - <group value="example"/> - </annotations> - <after> - <seeInCurrentUrl url="/admin/admin/" stepKey="seeInCurrentUrl"/> - </after> - <amOnPage url="{{AdminLoginPage.url}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="{{_ENV.MAGENTO_ADMIN_USERNAME}}" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml deleted file mode 100644 index 6a196c2c32c02..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="PersistMultipleEntitiesTest"> - <annotations> - <features value="SampleTests"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <before> - <createData entity="simplesubcategory" stepKey="simplecategory"/> - <createData entity="simpleproduct" stepKey="simpleproduct1"> - <requiredEntity createDataKey="simplecategory"/> - </createData> - <createData entity="simpleproduct" stepKey="simpleproduct2"> - <requiredEntity createDataKey="categoryLink"/> - </createData> - </before> - <after> - <deleteData createDataKey="simpleproduct1" stepKey="deleteProduct1"/> - <deleteData createDataKey="simpleproduct2" stepKey="deleteProduct2"/> - <deleteData createDataKey="simplecategory" stepKey="deleteCategory"/> - </after> - <amOnPage stepKey="s11" url="/$$simplecategory.name$$.html" /> - <waitForPageLoad stepKey="s33"/> - <see stepKey="s35" selector="{{StorefrontCategoryMainSection.productCount}}" userInput="2"/> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SampleTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SampleTest.xml deleted file mode 100644 index c107debc1aa62..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SampleTest.xml +++ /dev/null @@ -1,298 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- Test XML Example --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="PreAndPostHooksTest"> - <before> - <amOnUrl url="http://127.0.0.1:32772/admin/" stepKey="amOnPage"/> - <createData entity="CustomerEntity1" stepKey="createData1"/> - <createData entity="AssertThis" stepKey="createData2"/> - </before> - <after> - <amOnUrl url="http://127.0.0.1:32772/admin/admin/auth/logout" stepKey="amOnPage"/> - <deleteData createDataKey="createData1" stepKey="deleteData1"/> - <deleteData createDataKey="createData2" stepKey="deleteData2"/> - </after> - </test> - <test name="AllCodeceptionMethodsTest"> - <annotations> - <features value="SampleTests"/> - <title value="Create all Codeception methods"/> - <description value="Exercises the Generator to make sure it creates every Codeception method correctly."/> - <severity value="CRITICAL"/> - <testCaseId value="#"/> - </annotations> - <acceptPopup stepKey="acceptPopup"/> - <amOnPage url="/admin" stepKey="amOnPage"/> - <amOnSubdomain url="admin" stepKey="amOnSubdomain"/> - <amOnUrl url="http://www.google.com/" stepKey="amOnUrl"/> - <appendField userInput="More Words" selector=".stuff" stepKey="appendField"/> - <attachFile userInput="filename.php" selector="#stuff" stepKey="attachFile"/> - <cancelPopup stepKey="cancelPopup"/> - <checkOption selector="#checkbox" stepKey="checkOption"/> - <clearField selector="#field" stepKey="clearField"/> - <click selector="#button" userInput="Context" stepKey="click1"/> - <click selectorArray="['link' => 'Login']" stepKey="click2"/> - <click selectorArray="['link' => 'Login']" userInput="stuff" stepKey="click3"/> - <clickWithLeftButton selector="#clickHere" stepKey="clickWithLeftButton1" x="23" y="324"/> - <clickWithLeftButton selectorArray="['css' => '.checkout']" stepKey="clickWithLeftButton2" x="23" y="324"/> - <clickWithLeftButton stepKey="clickWithLeftButton3" x="23" y="324"/> - <clickWithRightButton selector="#clickHere" stepKey="clickWithRightButton1" x="23" y="324"/> - <clickWithRightButton selectorArray="['css' => '.checkout']" stepKey="clickWithRightButton2" x="23" y="324"/> - <clickWithRightButton stepKey="clickWithRightButton3" x="23" y="324"/> - <closeTab stepKey="closeTab"/> - <comment userInput="This is a Comment." stepKey="comment"/> - <createData entity="CustomerEntity1" stepKey="createData1"/> - <deleteData createDataKey="createData1" stepKey="deleteData1"/> - <dontSee userInput="Text" stepKey="dontSee1"/> - <dontSee userInput="Text" selector=".title" stepKey="dontSee2"/> - <dontSee userInput="Text" selectorArray="['css' => 'body h1']" stepKey="dontSee3"/> - <dontSeeCheckboxIsChecked selector="#checkbox" stepKey="dontSeeCheckboxIsChecked"/> - <dontSeeCookie userInput="cookieName" stepKey="dontSeeCookie1"/> - <dontSeeCookie userInput="cookieName" parameterArray="['domainName' => 'stuff']" stepKey="dontSeeCookie2"/> - <dontSeeCurrentUrlEquals url="/stuff" stepKey="dontSeeCurrentUrlEquals"/> - <dontSeeCurrentUrlMatches regex="~$/users/(\d+)~" stepKey="dontSeeCurrentUrlMatches"/> - <dontSeeElement selector=".error" stepKey="dontSeeElement1"/> - <dontSeeElement selector="input" parameterArray="['name' => 'login']" stepKey="dontSeeElement2"/> - <dontSeeElementInDOM selector="#stuff" stepKey="dontSeeElementInDOM1"/> - <dontSeeElementInDOM selector="#stuff" parameterArray="['name' => 'login']" stepKey="dontSeeElementInDOM2"/> - <dontSeeInCurrentUrl url="/users/" stepKey="dontSeeInCurrentUrl"/> - <dontSeeInField selector=".field" userInput="stuff" stepKey="dontSeeInField1"/> - <dontSeeInField selectorArray="['name' => 'search']" userInput="Comment Here" stepKey="dontSeeInField2"/> - <dontSeeInFormFields selector="form[name=myform]" parameterArray="['input1' => 'non-existent value', 'input2' => 'other non-existent value']" stepKey="dontSeeInFormFields"/> - <dontSeeInPageSource userInput="Stuff in Page Source" stepKey="dontSeeInPageSource"/> - <!--<dontSeeInSource html="<h1></h1>" stepKey="dontSeeInSource"/>--> - <dontSeeInTitle userInput="Title" stepKey="dontSeeInTitle"/> - <dontSeeLink userInput="Logout" stepKey="dontSeeLink1"/> - <dontSeeLink userInput="Checkout" url="/store/cart.php" stepKey="dontSeeLink2"/> - <dontSeeOptionIsSelected selector="#form .stuff" userInput="Option Name" stepKey="dontSeeOptionIsSelected"/> - <doubleClick selector="#click .here" stepKey="doubleClick"/> - <dragAndDrop selector1="#number1" selector2="#number2" stepKey="dragAndDrop"/> - <executeInSelenium function="function(\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {$webdriver->get('http://google.com');}" stepKey="executeInSelenium"/> - <executeJS function="return $('#myField').val()" stepKey="executeJS"/> - <fillField selector="#field" userInput="stuff" stepKey="fillField1"/> - <fillField selectorArray="['name' => 'email']" userInput="stuff" stepKey="fillField2"/> - <grabAttributeFrom selector="#target" userInput="title" stepKey="grabAttributeFrom"/> - <grabCookie userInput="cookie" parameterArray="['domain' => 'www.google.com']" stepKey="grabCookie"/> - <grabFromCurrentUrl regex="~$/user/(\d+)/~" stepKey="grabFromCurrentUrl"/> - <grabMultiple selector="a" userInput="href" stepKey="grabMultiple"/> - <grabPageSource stepKey="grabPageSource1"/> - <grabTextFrom selector="h1" stepKey="grabTextFrom1"/> - <grabValueFrom selector=".form" stepKey="grabValueFrom1"/> - <grabValueFrom selectorArray="['name' => 'username']" stepKey="grabValueFrom2"/> - <loadSessionSnapshot userInput="stuff" stepKey="loadSessionSnapshot1"/> - <loadSessionSnapshot userInput="stuff" stepKey="loadSessionSnapshot2"/> - <makeScreenshot userInput="ScreenshotName" stepKey="makeScreenshot"/> - <maximizeWindow stepKey="maximizeWindow"/> - <moveBack stepKey="moveBack"/> - <moveForward stepKey="moveForward"/> - <moveMouseOver selector="#stuff" stepKey="moveMouseOver1"/> - <moveMouseOver selectorArray="['css' => '.checkout']" stepKey="moveMouseOver2"/> - <moveMouseOver x="5" y="5" stepKey="moveMouseOver3"/> - <moveMouseOver selector="#stuff" x="5" y="5" stepKey="moveMouseOver4"/> - <moveMouseOver selectorArray="['css' => '.checkout']" x="5" y="5" stepKey="moveMouseOver5"/> - <openNewTab stepKey="openNewTab"/> - <pauseExecution stepKey="pauseExecution"/> - <performOn selector=".rememberMe" function="function (WebDriver $I) { $I->see('Remember me next time'); $I->seeElement('#LoginForm_rememberMe'); $I->dontSee('Login'); }" stepKey="performOn1"/> - <performOn selector=".rememberMe" function="ActionSequence::build()->see('Warning')->see('Are you sure you want to delete this?')->click('Yes')" stepKey="performOn2"/> - <pressKey selector="#page" userInput="a" stepKey="pressKey1"/> - <pressKey selector="#page" parameterArray="[['ctrl','a'],'new']" stepKey="pressKey2"/> - <pressKey selector="#page" parameterArray="[['shift','111'],'1','x']" stepKey="pressKey3"/> - <pressKey selector="#page" parameterArray="[['ctrl', 'a'], \Facebook\WebDriver\WebDriverKeys::DELETE]" stepKey="pressKey4"/> - <!--pressKey selector="descendant-or-self::*[@id='page']" userInput="u" stepKey="pressKey5"/--> - <reloadPage stepKey="reloadPage"/> - <resetCookie userInput="cookie" stepKey="resetCookie1"/> - <resetCookie userInput="cookie" parameterArray="['domainName' => 'www.google.com']" stepKey="resetCookie2"/> - <resizeWindow width="800" height="600" stepKey="resizeWindow"/> - <saveSessionSnapshot userInput="stuff" stepKey="saveSessionSnapshot"/> - <scrollTo selector="#place" x="20" y="50" stepKey="scrollTo1"/> - <scrollTo selectorArray="['css' => '.checkout']" x="20" y="50" stepKey="scrollTo2"/> - <see userInput="Stuff" stepKey="see1"/> - <see userInput="More Stuff" selector=".stuff" stepKey="see2"/> - <see userInput="More More Stuff" selectorArray="['css' => 'body h1']" stepKey="see3"/> - <seeCheckboxIsChecked selector="#checkbox" stepKey="seeCheckboxIsChecked"/> - <seeCookie userInput="PHPSESSID" stepKey="seeCookie1"/> - <seeCookie userInput="PHPSESSID" parameterArray="['domainName' => 'www.google.com']" stepKey="seeCookie2"/> - <seeCurrentUrlEquals url="/" stepKey="seeCurrentUrlEquals"/> - <seeCurrentUrlMatches regex="~$/users/(\d+)~" stepKey="seeCurrentUrlMatches"/> - <seeElement selector=".error" stepKey="seeElement1"/> - <seeElement selectorArray="['css' => 'form input']" stepKey="seeElement2"/> - <seeElement selector=".error" parameterArray="['name' => 'login']" stepKey="seeElement3"/> - <seeElement selectorArray="['css' => 'form input']" parameterArray="['name' => 'login']" stepKey="seeElement4"/> - <seeElementInDOM selector="//form/input[type=hidden]" stepKey="seeElementInDOM1"/> - <seeElementInDOM selector="//form/input[type=hidden]" parameterArray="['name' => 'form']" stepKey="seeElementInDOM2"/> - <seeInCurrentUrl url="home" stepKey="seeInCurrentUrl1"/> - <seeInCurrentUrl url="/home/" stepKey="seeInCurrentUrl2"/> - <seeInField userInput="Stuff" selector="#field" stepKey="seeInField1"/> - <seeInField userInput="Stuff" selectorArray="['name' => 'search']" stepKey="seeInField2"/> - <seeInFormFields selector="form[name=myform]" parameterArray="['input1' => 'value','input2' => 'other value']" stepKey="seeInFormFields1"/> - <seeInFormFields selector=".form-class" parameterArray="[['multiselect' => ['value1','value2'],'checkbox[]]' => ['a checked value','another checked value',]]" stepKey="seeInFormFields2"/> - <!--<seeInPageSource html="<h1></h1>" stepKey="seeInPageSource"/>--> - <seeInPopup userInput="Yes in Popup" stepKey="seeInPopup"/> - <!--<seeInSource html="<h1></h1>" stepKey="seeInSource"/>--> - <seeInTitle userInput="In Title" stepKey="seeInTitle"/> - <seeLink userInput="Logout" stepKey="seeLink1"/> - <seeLink userInput="Logout" url="/logout" stepKey="seeLink2"/> - <seeNumberOfElements selector="tr" userInput="10" stepKey="seeNumberOfElements1"/> - <seeNumberOfElements selector="tr" userInput="[0, 10]" stepKey="seeNumberOfElements2"/> - <seeOptionIsSelected selector=".option" userInput="Visa" stepKey="seeOptionIsSelected"/> - <selectOption selector=".dropDown" userInput="Option Name" stepKey="selectOption1"/> - <selectOption selector="//form/select[@name=account]" parameterArray="['Windows','Linux']" stepKey="selectOption2"/> - <selectOption selector="Which OS do you use?" parameterArray="['text' => 'Windows']" stepKey="selectOption3"/> - <setCookie userInput="PHPSESSID" value="stuff" stepKey="setCookie1"/> - <setCookie userInput="PHPSESSID" value="stuff" parameterArray="['domainName' => 'www.google.com']" stepKey="setCookie2"/> - <submitForm selector="#my-form" parameterArray="['field' => ['value','another value',]]" button="#submit" stepKey="submitForm2"/> - <switchToIFrame stepKey="switchToIFrame1"/> - <switchToIFrame userInput="another_frame" stepKey="switchToIFrame2"/> - <switchToNextTab stepKey="switchToNextTab1"/> - <switchToNextTab userInput="2" stepKey="switchToNextTab2"/> - <switchToPreviousTab stepKey="switchToPreviewTab1"/> - <switchToPreviousTab userInput="1" stepKey="switchToPreviewTab2"/> - <switchToWindow stepKey="switchToWindow1"/> - <switchToWindow userInput="another_window" stepKey="switchToWindow2"/> - <typeInPopup userInput="Stuff for popup" stepKey="typeInPopup"/> - <uncheckOption selector="#option" stepKey="uncheckOption"/> - <unselectOption selector="#dropDown" userInput="Option" stepKey="unselectOption"/> - <wait time="15" stepKey="wait"/> - <waitForElement selector="#button" time="10" stepKey="waitForElement"/> - <waitForElementChange selector="#menu" function="function(\WebDriverElement $el) {return $el->isDisplayed();}" time="100" stepKey="waitForElementChange"/> - <waitForElementNotVisible selector="#a_thing .className" time="30" stepKey="waitForElementNotVisible"/> - <waitForElementVisible selector="#a_thing .className" time="15" stepKey="waitForElementVisible"/> - <waitForJS function="return $.active == 0;" time="30" stepKey="waitForJS"/> - <waitForText userInput="foo" time="30" stepKey="waitForText1"/> - <waitForText userInput="foo" selector=".title" time="30" stepKey="waitForText2"/> - </test> - <test name="AllCustomMethodsTest"> - <annotations> - <title value="Create all Custom methods"/> - <description value="Exercises the Generator to make sure it creates every Custom method correctly."/> - <severity value="CRITICAL"/> - <testCaseId value="#"/> - </annotations> - <assertElementContainsAttribute selector="#username" attribute="class" expectedValue="admin__control-text" stepKey="assertElementContainsAttribute1"/> - <assertElementContainsAttribute selector="#username" attribute="type" expectedValue="text" stepKey="assertElementContainsAttribute2"/> - <assertElementContainsAttribute selector="#username" attribute="name" expectedValue="login[username]" stepKey="assertElementContainsAttribute3"/> - <assertElementContainsAttribute selector="#username" attribute="autofocus" expectedValue="" stepKey="assertElementContainsAttribute4"/> - <assertElementContainsAttribute selector="#username" attribute="data-validate" expectedValue="{required:true}" stepKey="assertElementContainsAttribute5"/> - <assertElementContainsAttribute selector="#username" attribute="placeholder" expectedValue="user name" stepKey="assertElementContainsAttribute6"/> - <assertElementContainsAttribute selector="#username" attribute="autocomplete" expectedValue="off" stepKey="assertElementContainsAttribute7"/> - <assertElementContainsAttribute selector=".admin__menu-overlay" attribute="style" expectedValue="display: none;" stepKey="assertElementContainsAttribute8"/> - <assertElementContainsAttribute selector=".admin__menu-overlay" attribute="border" expectedValue="0" stepKey="assertElementContainsAttribute9"/> - <closeAdminNotification stepKey="closeAdminNotification1"/> - <searchAndMultiSelectOption selector="#stuff" parameterArray="['Item 1', 'Item 2']" stepKey="searchAndMultiSelect1"/> - <searchAndMultiSelectOption selector="#stuff" parameterArray="['Item 1', 'Item 2']" requiredAction="true" stepKey="searchAndMultiSelect2"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <waitForPageLoad time="15" stepKey="waitForPageLoad2"/> - <waitForAjaxLoad stepKey="waitForAjax1"/> - <waitForAjaxLoad time="15" stepKey="waitForAjax2"/> - <dontSeeJsError stepKey="dontSeeJsError"/> - <formatMoney userInput="$300,000" stepKey="formatMoney1"/> - <formatMoney userInput="$300,000" locale="en_US.UTF-8" stepKey="formatMoney2"/> - <mSetLocale userInput="300" locale="en_US.UTF-8" stepKey="mSetLocale1"/> - <mResetLocale stepKey="mResetLocale1"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> - <scrollToTopOfPage stepKey="scrollToTopOfPage"/> - <parseFloat userInput="300,000.2325" stepKey="parseFloat1"/> - <magentoCLI stepKey="enableMaintenance1" command="maintenance:enable"/> - </test> - <test name="AllVariableMethodsTest"> - <annotations> - <features value="SampleTests"/> - <title value="Create all Methods that support Variables."/> - <description value="Exercises the Generator to make sure it creates every Method that supports a Variable."/> - <severity value="CRITICAL"/> - <testCaseId value="#"/> - </annotations> - <grabFromCurrentUrl stepKey="grabFromCurrentUrl1"/> - <amOnPage url="{$randomStuff}" stepKey="amOnPage1"/> - <amOnSubdomain url="{$randomStuff}" stepKey="amOnSubdomain1"/> - <amOnUrl url="{$randomStuff}" stepKey="amOnUrl1"/> - <appendField userInput="{$randomStuff}" selector="#randomField" stepKey="appendField1"/> - <attachFile userInput="{$randomStuff}" selector="#filePathField" stepKey="attachFile1"/> - <click userInput="{$randomStuff}" stepKey="click1"/> - <dontSee userInput="{$randomStuff}" stepKey="dontSee1"/> - <dontSeeCookie userInput="{$randomStuff}" stepKey="dontSeeCookie1"/> - <dontSeeCurrentUrlEquals url="{$randomStuff}" stepKey="dontSeeCurrentUrlEquals1"/> - <dontSeeCurrentUrlMatches regex="{$randomStuff}" stepKey="dontSeeCurrentUrlMatches1"/> - <dontSeeInCurrentUrl url="{$randomStuff}" stepKey="dontSeeInCurrentUrl1"/> - <dontSeeInField selector="#stuff" userInput="{$randomStuff}" stepKey="dontSeeInField1"/> - <dontSeeInPageSource userInput="{$randomStuff}" stepKey="dontSeeInPageSource1"/> - <dontSeeInTitle userInput="{$randomStuff}" stepKey="dontSeeInTitle1"/> - <dontSeeLink userInput="{$randomStuff}" stepKey="dontSeeLink1"/> - <dontSeeOptionIsSelected selector="#dropdown" userInput="{$randomStuff}" stepKey="dontSeeOptionIsSelected1"/> - <fillField userInput="{$randomStuff}" selector="#field" stepKey="fillField1"/> - <grabAttributeFrom selector="#stuff" userInput="{$randomStuff}" stepKey="grabAttributeFrom1"/> - <grabCookie userInput="{$randomStuff}" stepKey="grabValueFrom1"/> - <grabFromCurrentUrl regex="{$randomStuff}" stepKey="grabFromCurrentUrl"/> - <grabMultiple selector="a" userInput="{$randomStuff}" stepKey="grabMultiple1"/> - <loadSessionSnapshot userInput="{$randomStuff}" stepKey="loadSessionSnapshot"/> - <pressKey selector="a" userInput="{$randomStuff}" stepKey="pressKey1"/> - <saveSessionSnapshot userInput="{$randomStuff}" stepKey="saveSessionSnapshot1"/> - <see userInput="{$randomStuff}" stepKey="see1"/> - <seeCookie userInput="{$randomStuff}" stepKey="seeCookie1"/> - <seeCurrentUrlEquals url="{$randomStuff}" stepKey="seeCurrentUrlEquals1"/> - <seeCurrentUrlMatches regex="{$randomStuff}" stepKey="seeCurrentUrlMatches1"/> - <seeInCurrentUrl url="{$randomStuff}" stepKey="seeInCurrentUrl1"/> - <seeInField selector="a" userInput="{$randomStuff}" stepKey="seeInField1"/> - <seeInPopup userInput="{$randomStuff}" stepKey="seeInPopup"/> - <seeInTitle userInput="{$randomStuff}" stepKey="seeInTitle1"/> - <seeLink userInput="{$randomStuff}" stepKey="seeLink1"/> - <seeNumberOfElements selector="#stuff" userInput="{$randomStuff}" stepKey="seeNumberOfElements1"/> - <seeOptionIsSelected selector="#stuff" userInput="{$randomStuff}" stepKey="seeOptionIsSelected1"/> - <selectOption selector="#stuff" userInput="{$randomStuff}" stepKey="selectOption1"/> - <switchToIFrame userInput="{$randomStuff}" stepKey="switchToIFrame1"/> - <switchToNextTab userInput="{$randomStuff}" stepKey="switchToNextTab2"/> - <switchToPreviousTab userInput="{$randomStuff}" stepKey="switchToPreviousTab1"/> - <switchToNextTab userInput="{$randomStuff}" stepKey="switchToNextTab3"/> - <switchToWindow userInput="{$randomStuff}" stepKey="switchToWindow1"/> - <typeInPopup userInput="{$randomStuff}" stepKey="typeInPopup"/> - <unselectOption selector="#option" userInput="{$randomStuff}" stepKey="unselectOption1"/> - <waitForText userInput="{$randomStuff}" time="5" stepKey="waitForText1"/> - </test> - <test name="AllReplacementTest"> - <annotations> - <features value="SampleTests"/> - <title value="Exercise reference replacement."/> - <description value="Exercises {{foo}}, $foo$, and $$foo$$ replacement."/> - <severity value="CRITICAL"/> - <testCaseId value="#"/> - </annotations> - - <createData entity="CustomerEntity1" stepKey="testScopeData"/> - <createData entity="AssertThis" stepKey="testScopeData2"/> - - <!-- parameterized url that uses literal params --> - <amOnPage url="{{SamplePage.url('success','success2')}}" stepKey="a0"/> - - <!-- url referencing data that was created in this <test> --> - <amOnPage url="$testScopeData.firstname$.html" stepKey="a1"/> - - <!-- url referencing data that was created in a <before> --> - <amOnPage url="$$createData1.firstname$$.html" stepKey="a2"/> - - <!-- parameterized url that uses created data params --> - <amOnPage url="{{SamplePage.url($testScopeData.firstname$,$testScopeData.lastname$)}}" stepKey="a3"/> - <amOnPage url="{{SamplePage.url($$createData1.firstname$$,$$createData1.lastname$$)}}" stepKey="a4"/> - - <!-- parameterized selector that uses literal params --> - <click selector="{{SampleSection.oneParamElement('success')}}" stepKey="c1"/> - <click selector="{{SampleSection.twoParamElement('success','success2')}}" stepKey="c2"/> - - <!-- parameterized selector with literal, static data, and created data --> - <click selector="{{SampleSection.threeParamElement('John', SamplePerson.lastname, $testScopeData.lastname$)}}" stepKey="c3"/> - - <!-- selector that uses created data --> - <click selector="#$testScopeData.firstname$ .$testScopeData.lastname$" stepKey="c4"/> - <click selector="#$$createData1.firstname$$ .$$createData1.lastname$$" stepKey="c5"/> - - <!-- userInput that uses created data --> - <fillField selector="#sample" userInput="Hello $testScopeData.firstname$ $testScopeData.lastname$" stepKey="f1"/> - <fillField selector="#sample" userInput="Hello $$createData1.firstname$$ $$createData1.lastname$$" stepKey="f2"/> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml deleted file mode 100644 index f908c5cb4572e..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="SetPaypalConfigurationTest"> - <annotations> - <features value="SampleTests"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <createData entity="SamplePaypalConfig" stepKey="createSamplePaypalConfig"/> - <createData entity="DefaultPayPalConfig" stepKey="restoreDefaultPaypalConfig"/> - </test> - <test name="SetBraintreeConfigurationTest"> - <annotations> - <features value="SampleTests"/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <createData entity="SampleBraintreeConfig" stepKey="createSampleBraintreeConfig"/> - <createData entity="DefaultBraintreeConfig" stepKey="restoreDefaultBraintreeConfig"/> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml deleted file mode 100644 index b18c24050d3a6..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="UpdateSimpleProductByApiTest"> - <annotations> - <features value="SampleTests"/> - <stories value="Update simple product by api test."/> - <skip> - <issueId value="SAMPLE"/> - </skip> - </annotations> - <before> - <createData stepKey="categoryHandle" entity="SimpleSubCategory"/> - <createData stepKey="productHandle" entity="SimpleProduct" > - <requiredEntity createDataKey="categoryHandle"/> - </createData> - <updateData stepKey="updateProduct" entity="NewSimpleProduct" createDataKey="productHandle"/> - </before> - <after> - <deleteData stepKey="delete" createDataKey="updateProduct"/> - </after> - </test> -</tests> \ No newline at end of file From 2510c4af6f8bb5b67b87c65853e977a3d0baccc8 Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Mon, 1 Oct 2018 15:38:12 -0500 Subject: [PATCH 071/118] MC-4303: Functional tests failure with the installed Dotmailer module --- .../Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml | 2 +- .../Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml index 71a876bbbcdbf..beb2c2bffa135 100644 --- a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml +++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml @@ -13,7 +13,7 @@ <waitForPageLoad stepKey="waitForStoresLoaded"/> <click selector="{{CaptchaFormsDisplayingSection.config}}" stepKey="ClickToGoConfiguration"/> <waitForPageLoad stepKey="waitForConfigurationsLoaded"/> - <scrollTo selector="{{CaptchaFormsDisplayingSection.customer}}" stepKey="ScrollToCustomers"/> + <scrollTo selector="{{CaptchaFormsDisplayingSection.customer}}" x="0" y="-80" stepKey="ScrollToCustomers"/> <click selector="{{CaptchaFormsDisplayingSection.customer}}" stepKey="ClickToCustomers"/> <waitForPageLoad stepKey="waitForCustomerConfigurationsLoaded"/> <click selector="{{CaptchaFormsDisplayingSection.customerConfig}}" stepKey="ClickToGoCustomerConfiguration"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml index ed08c84cdb6f8..7a9de9670f216 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml @@ -15,7 +15,7 @@ <element name="apply" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> <element name="filter" type="button" selector="//div[@class='data-grid-filters-action-wrap']/button" timeout="30"/> <element name="typeDropDown" type="multiselect" selector="//select[@name='type_id']" timeout="30"/> - <element name="bundleOption" type="multiselect" selector="//select[@name='type_id']/option[4]" timeout="30"/> + <element name="bundleOption" type="multiselect" selector="//select[@name='type_id']/option[@value='bundle']" timeout="30"/> <element name="applyFilters" type="button" selector="//button[@class='action-secondary']" timeout="30"/> <element name="allCheckbox" type="checkbox" selector="//div[@data-role='grid-wrapper']//label[@data-bind='attr: {for: ko.uid}']" timeout="30"/> <element name="actions" type="button" selector="//div[@class='action-select-wrap']/button" timeout="30"/> From 0c42ce29764cd1198a2d84ac0509891b7801934e Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@adobe.com> Date: Mon, 1 Oct 2018 17:31:28 -0500 Subject: [PATCH 072/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - updated test to comment out a step to fillField --- .../Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 66316d0af8b60..e4fd894f608c5 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -120,10 +120,9 @@ <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreateCreditMemo" after="createCreditMemoComment"/> <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> - <!--Update Qty of items to be refunded and submit refund--> + <!--Submit refund--> <scrollTo selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" stepKey="scrollToItemsToRefund"/> - <fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" stepKey="fillQtyOfItemsToRefund" after="scrollToItemsToRefund"/> - + <!--<fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" stepKey="fillQtyOfItemsToRefund" after="scrollToItemsToRefund"/>--> <!--<click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/>--> <waitForLoadingMaskToDisappear stepKey="waitForRefundQtyToUpdate"/> <waitForElementVisible selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="seeSubmitRefundBtn"/> From 069aa1c014ef872ba5b353fa08a2359e66cbe630 Mon Sep 17 00:00:00 2001 From: "Vasiliev.A" <a.vasiliev@sam-solutions.biz> Date: Mon, 17 Sep 2018 14:30:40 +0300 Subject: [PATCH 073/118] add support HTTP DELETE method for async bulk request by adding merging url params with body params --- .../Controller/Rest/Asynchronous/InputParamsResolver.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php b/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php index e6df38c563ed1..4ebb23f33e97b 100644 --- a/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php +++ b/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php @@ -95,6 +95,13 @@ public function resolve() $this->requestValidator->validate(); $webapiResolvedParams = []; $inputData = $this->request->getRequestData(); + + $httpMethod = $this->request->getHttpMethod(); + if ($httpMethod == \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE) { + $requestBodyParams = $this->request->getBodyParams(); + $inputData = array_merge($requestBodyParams, $inputData); + } + foreach ($inputData as $key => $singleEntityParams) { $webapiResolvedParams[$key] = $this->resolveBulkItemParams($singleEntityParams); } From 9a757cbbf2013fa849d13fe3d4775ec8cd38b6dc Mon Sep 17 00:00:00 2001 From: Volodymyr Kublytskyi <vkublytskyi@magento.com> Date: Tue, 2 Oct 2018 17:28:09 +0300 Subject: [PATCH 074/118] MAGETWO-94762: Amqp Logic Exception - fix magento/bulk-api-ce#28 --- .../Model/Cron/ConsumersRunner.php | 59 ++++++++++++++++--- .../Unit/Model/Cron/ConsumersRunnerTest.php | 13 +++- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php b/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php index f301fb9289efb..f5011248d7772 100644 --- a/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php +++ b/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php @@ -5,9 +5,13 @@ */ namespace Magento\MessageQueue\Model\Cron; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\MessageQueue\ConnectionTypeResolver; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItemInterface; use Magento\Framework\ShellInterface; use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfigInterface; use Magento\Framework\App\DeploymentConfig; +use Psr\Log\LoggerInterface; use Symfony\Component\Process\PhpExecutableFinder; use Magento\MessageQueue\Model\Cron\ConsumersRunner\PidConsumerManager; @@ -56,6 +60,16 @@ class ConsumersRunner */ private $pidConsumerManager; + /** + * @var ConnectionTypeResolver + */ + private $mqConnectionTypeResolver; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @param PhpExecutableFinder $phpExecutableFinder The executable finder specifically designed * for the PHP executable @@ -63,19 +77,27 @@ class ConsumersRunner * @param DeploymentConfig $deploymentConfig The application deployment configuration * @param ShellInterface $shellBackground The shell command line wrapper for executing command in background * @param PidConsumerManager $pidConsumerManager The class for checking status of process by PID + * @param ConnectionTypeResolver $mqConnectionTypeResolver Consumer connection resolver + * @param LoggerInterface $logger Logger */ public function __construct( PhpExecutableFinder $phpExecutableFinder, ConsumerConfigInterface $consumerConfig, DeploymentConfig $deploymentConfig, ShellInterface $shellBackground, - PidConsumerManager $pidConsumerManager + PidConsumerManager $pidConsumerManager, + ConnectionTypeResolver $mqConnectionTypeResolver = null, + LoggerInterface $logger = null ) { $this->phpExecutableFinder = $phpExecutableFinder; $this->consumerConfig = $consumerConfig; $this->deploymentConfig = $deploymentConfig; $this->shellBackground = $shellBackground; $this->pidConsumerManager = $pidConsumerManager; + $this->mqConnectionTypeResolver = $mqConnectionTypeResolver + ?: ObjectManager::getInstance()->get(ConnectionTypeResolver::class); + $this->logger = $logger + ?: ObjectManager::getInstance()->get(LoggerInterface::class); } /** @@ -94,12 +116,12 @@ public function run() $php = $this->phpExecutableFinder->find() ?: 'php'; foreach ($this->consumerConfig->getConsumers() as $consumer) { - $consumerName = $consumer->getName(); - - if (!$this->canBeRun($consumerName, $allowedConsumers)) { + if (!$this->canBeRun($consumer, $allowedConsumers)) { continue; } + $consumerName = $consumer->getName(); + $arguments = [ $consumerName, '--pid-file-path=' . $this->getPidFilePath($consumerName), @@ -119,16 +141,37 @@ public function run() /** * Checks that the consumer can be run * - * @param string $consumerName The consumer name + * @param ConsumerConfigItemInterface $consumerConfig The consumer config * @param array $allowedConsumers The list of allowed consumers * If $allowedConsumers is empty it means that all consumers are allowed * @return bool Returns true if the consumer can be run + * @throws \Magento\Framework\Exception\FileSystemException */ - private function canBeRun($consumerName, array $allowedConsumers = []) + private function canBeRun(ConsumerConfigItemInterface $consumerConfig, array $allowedConsumers = []): bool { - $allowed = empty($allowedConsumers) ?: in_array($consumerName, $allowedConsumers); + $consumerName = $consumerConfig->getName(); + if (!empty($allowedConsumers) && !in_array($consumerName, $allowedConsumers)) { + return false; + } + + if ($this->pidConsumerManager->isRun($this->getPidFilePath($consumerName))) { + return false; + } + + $connectionName = $consumerConfig->getConnection(); + try { + $this->mqConnectionTypeResolver->getConnectionType($connectionName); + } catch (\LogicException $e) { + $this->logger->info(sprintf( + 'Consumer "%s" skipped as required connection "%s" is not configured. %s', + $consumerName, + $connectionName, + $e->getMessage() + )); + return false; + } - return $allowed && !$this->pidConsumerManager->isRun($this->getPidFilePath($consumerName)); + return true; } /** diff --git a/app/code/Magento/MessageQueue/Test/Unit/Model/Cron/ConsumersRunnerTest.php b/app/code/Magento/MessageQueue/Test/Unit/Model/Cron/ConsumersRunnerTest.php index bf8796a03f52a..006354b997d3a 100644 --- a/app/code/Magento/MessageQueue/Test/Unit/Model/Cron/ConsumersRunnerTest.php +++ b/app/code/Magento/MessageQueue/Test/Unit/Model/Cron/ConsumersRunnerTest.php @@ -5,6 +5,7 @@ */ namespace Magento\MessageQueue\Test\Unit\Model\Cron; +use Magento\Framework\MessageQueue\ConnectionTypeResolver; use \PHPUnit_Framework_MockObject_MockObject as MockObject; use Magento\Framework\ShellInterface; use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfigInterface; @@ -41,6 +42,11 @@ class ConsumersRunnerTest extends \PHPUnit\Framework\TestCase */ private $phpExecutableFinderMock; + /** + * @var ConnectionTypeResolver + */ + private $connectionTypeResover; + /** * @var ConsumersRunner */ @@ -66,13 +72,18 @@ protected function setUp() $this->deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) ->disableOriginalConstructor() ->getMock(); + $this->connectionTypeResover = $this->getMockBuilder(ConnectionTypeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->connectionTypeResover->method('getConnectionType')->willReturn('something'); $this->consumersRunner = new ConsumersRunner( $this->phpExecutableFinderMock, $this->consumerConfigMock, $this->deploymentConfigMock, $this->shellBackgroundMock, - $this->pidConsumerManagerMock + $this->pidConsumerManagerMock, + $this->connectionTypeResover ); } From e402fc8ef52b53933e51ede14dce304ab47d378c Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Tue, 2 Oct 2018 13:27:32 -0500 Subject: [PATCH 075/118] MC-4303: Functional tests failure with the installed Dotmailer module --- app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml index 82f5b515eb967..0032a6c987e82 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml @@ -68,6 +68,7 @@ <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoice"/> <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <waitForPageLoad stepKey="waitForInvoicePageLoad"/> <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeSuccessMessage"/> <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoices"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask5" /> From 39fbd1dadc81f837aaf2d8ec8f5615a55a2abff7 Mon Sep 17 00:00:00 2001 From: Alex Paliarush <paliarus@adobe.com> Date: Tue, 2 Oct 2018 15:53:31 -0500 Subject: [PATCH 076/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization --- .../Model/Resolver/LayerFilters.php | 49 +++++++++++++++++++ .../Model/Resolver/Products.php | 12 ++--- .../CatalogGraphQl/etc/schema.graphqls | 2 +- .../GraphQl/Query/ResolverInterface.php | 3 +- 4 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/LayerFilters.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/LayerFilters.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/LayerFilters.php new file mode 100644 index 0000000000000..0ec7e12e42d55 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/LayerFilters.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; + +/** + * Layered navigation filters resolver, used for GraphQL request processing. + */ +class LayerFilters implements ResolverInterface +{ + /** + * @var Layer\DataProvider\Filters + */ + private $filtersDataProvider; + + /** + * @param \Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters $filtersDataProvider + */ + public function __construct( + \Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters $filtersDataProvider + ) { + $this->filtersDataProvider = $filtersDataProvider; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (!isset($value['layer_type'])) { + return null; + } + + return $this->filtersDataProvider->getData($value['layer_type']); + } +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php index 0f618058e06df..47da945c2cce2 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php @@ -42,28 +42,22 @@ class Products implements ResolverInterface */ private $searchFilter; - /** - * @var Layer\DataProvider\Filters - */ - private $filtersDataProvider; - /** * @param Builder $searchCriteriaBuilder * @param Search $searchQuery * @param Filter $filterQuery + * @param SearchFilter $searchFilter */ public function __construct( Builder $searchCriteriaBuilder, Search $searchQuery, Filter $filterQuery, - SearchFilter $searchFilter, - \Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters $filtersDataProvider + SearchFilter $searchFilter ) { $this->searchCriteriaBuilder = $searchCriteriaBuilder; $this->searchQuery = $searchQuery; $this->filterQuery = $filterQuery; $this->searchFilter = $searchFilter; - $this->filtersDataProvider = $filtersDataProvider; } /** @@ -115,7 +109,7 @@ public function resolve( 'page_size' => $searchCriteria->getPageSize(), 'current_page' => $currentPage ], - 'filters' => $this->filtersDataProvider->getData($layerType) + 'layer_type' => $layerType ]; return $data; diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 9235ec271a3c2..e80e6846bf9d0 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -415,7 +415,7 @@ type Products @doc(description: "The Products object is the top-level object ret items: [ProductInterface] @doc(description: "An array of products that match the specified search criteria") page_info: SearchResultPageInfo @doc(description: "An object that includes the page_info and currentPage values specified in the query") total_count: Int @doc(description: "The number of products returned") - filters: [LayerFilter] @doc(description: "Layered navigation filters array") + filters: [LayerFilter] @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\LayerFilters") @doc(description: "Layered navigation filters array") sort_fields: SortFields @doc(description: "An object that includes the default sort field and all available sort fields") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\SortFields") } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/ResolverInterface.php b/lib/internal/Magento/Framework/GraphQl/Query/ResolverInterface.php index 295113a98e465..c7b4c7688b9ab 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/ResolverInterface.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/ResolverInterface.php @@ -10,6 +10,7 @@ use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\Resolver\Value; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; /** * Resolver fetches the data and formats it according to the GraphQL schema. @@ -20,7 +21,7 @@ interface ResolverInterface * Fetches the data from persistence models and format it according to the GraphQL schema. * * @param \Magento\Framework\GraphQl\Config\Element\Field $field - * @param $context + * @param ContextInterface $context * @param ResolveInfo $info * @param array|null $value * @param array|null $args From b8b6adea3d2f593d9f0c9c2ff926d217dbc7814d Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Wed, 3 Oct 2018 09:51:12 -0500 Subject: [PATCH 077/118] MAGETWO-95238: Cannot reset customer password from Admin Panel --- .../Adminhtml/Edit/ResetPasswordButton.php | 9 ++++++++- .../view/adminhtml/web/edit/post-wrapper.js | 8 ++++++++ .../Adminhtml/Index/ResetPasswordTest.php | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/ResetPasswordButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/ResetPasswordButton.php index f2d1dd9f0a853..c38f182f275f2 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/ResetPasswordButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/ResetPasswordButton.php @@ -13,6 +13,8 @@ class ResetPasswordButton extends GenericButton implements ButtonProviderInterface { /** + * Retrieve button-specified settings + * * @return array */ public function getButtonData() @@ -23,7 +25,10 @@ public function getButtonData() $data = [ 'label' => __('Reset Password'), 'class' => 'reset reset-password', - 'on_click' => sprintf("location.href = '%s';", $this->getResetPasswordUrl()), + 'data_attribute' => [ + 'url' => $this->getResetPasswordUrl() + ], + 'on_click' => '', 'sort_order' => 60, ]; } @@ -31,6 +36,8 @@ public function getButtonData() } /** + * Get reset password url + * * @return string */ public function getResetPasswordUrl() diff --git a/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js b/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js index 76b060015c5ff..27fa5eb783bba 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js +++ b/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js @@ -44,4 +44,12 @@ define([ return false; }); + + $('#resetPassword').click(function () { + var url = $('#resetPassword').data('url'); + + getForm(url).appendTo('body').submit(); + + return false; + }); }); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ResetPasswordTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ResetPasswordTest.php index eaaba639d49a8..8fa77a7388be2 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ResetPasswordTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ResetPasswordTest.php @@ -43,6 +43,23 @@ public function testResetPasswordSuccess() $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl . 'edit')); } + /** + * Checks reset password functionality cannot be performed with GET request + * + * @magentoConfigFixture current_store customer/password/limit_password_reset_requests_method 0 + * @magentoConfigFixture current_store customer/password/min_time_between_password_reset_requests 0 + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testResetPasswordWithGet() + { + $this->passwordResetRequestEventCreate( + \Magento\Security\Model\PasswordResetRequestEvent::CUSTOMER_PASSWORD_RESET_REQUEST + ); + $this->getRequest()->setPostValue(['customer_id' => '1'])->setMethod(HttpRequest::METHOD_GET); + $this->dispatch('backend/customer/index/resetPassword'); + $this->assertEquals('noroute', $this->getRequest()->getControllerName()); + } + /** * Checks reset password functionality with default restrictive min time between * password reset requests and customer reset request event. From 83e0f7fdf69c6c32c8061824ac2e4e85c512adb2 Mon Sep 17 00:00:00 2001 From: Hwashiang Yu <hwyu@adobe.com> Date: Thu, 27 Sep 2018 14:15:04 -0500 Subject: [PATCH 078/118] MC-4063: Flaky MFTF Test: AdminRemoveDefaultImageDownloadableProductTest - Unskipped AdminRemoveDefaultImageDownloadableProductTest --- .../Test/AdminRemoveDefaultImageDownloadableProductTest.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml b/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml index 6e3e7f7d17146..3ee6cef47738b 100644 --- a/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml +++ b/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml @@ -17,9 +17,6 @@ <severity value="MAJOR"/> <testCaseId value="MC-201"/> <group value="Downloadable"/> - <skip> - <issueId value="MC-4063"/> - </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> From 85cd771b9bffe661e76f5587b2ed935d3097a772 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 3 Oct 2018 14:45:17 -0500 Subject: [PATCH 079/118] MAGETWO-95130: CMS block cannot be deleted - Reapplied the changes from the original fix --- .../Cms/Block/Adminhtml/Block/Edit/DeleteButton.php | 6 ++++-- .../Cms/Block/Adminhtml/Page/Edit/DeleteButton.php | 6 ++++-- .../Ui/Component/Listing/Column/BlockActionsTest.php | 1 + .../Unit/Ui/Component/Listing/Column/PageActionsTest.php | 1 + .../Cms/Ui/Component/Listing/Column/BlockActions.php | 9 ++++----- .../Cms/Ui/Component/Listing/Column/PageActions.php | 9 ++++----- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Cms/Block/Adminhtml/Block/Edit/DeleteButton.php b/app/code/Magento/Cms/Block/Adminhtml/Block/Edit/DeleteButton.php index a7410cac64d76..51a9313fdefd2 100644 --- a/app/code/Magento/Cms/Block/Adminhtml/Block/Edit/DeleteButton.php +++ b/app/code/Magento/Cms/Block/Adminhtml/Block/Edit/DeleteButton.php @@ -13,7 +13,7 @@ class DeleteButton extends GenericButton implements ButtonProviderInterface { /** - * @return array + * @inheritDoc */ public function getButtonData() { @@ -24,7 +24,7 @@ public function getButtonData() 'class' => 'delete', 'on_click' => 'deleteConfirm(\'' . __( 'Are you sure you want to do this?' - ) . '\', \'' . $this->getDeleteUrl() . '\')', + ) . '\', \'' . $this->getDeleteUrl() . '\', {"data": {}})', 'sort_order' => 20, ]; } @@ -32,6 +32,8 @@ public function getButtonData() } /** + * URL to send delete requests to. + * * @return string */ public function getDeleteUrl() diff --git a/app/code/Magento/Cms/Block/Adminhtml/Page/Edit/DeleteButton.php b/app/code/Magento/Cms/Block/Adminhtml/Page/Edit/DeleteButton.php index 1fc599e4c856a..b434fd3f5d348 100644 --- a/app/code/Magento/Cms/Block/Adminhtml/Page/Edit/DeleteButton.php +++ b/app/code/Magento/Cms/Block/Adminhtml/Page/Edit/DeleteButton.php @@ -13,7 +13,7 @@ class DeleteButton extends GenericButton implements ButtonProviderInterface { /** - * @return array + * @inheritDoc */ public function getButtonData() { @@ -24,7 +24,7 @@ public function getButtonData() 'class' => 'delete', 'on_click' => 'deleteConfirm(\'' . __( 'Are you sure you want to do this?' - ) . '\', \'' . $this->getDeleteUrl() . '\')', + ) . '\', \'' . $this->getDeleteUrl() . '\', {"data": {}})', 'sort_order' => 20, ]; } @@ -32,6 +32,8 @@ public function getButtonData() } /** + * Url to send delete requests to. + * * @return string */ public function getDeleteUrl() diff --git a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php index 3dcf6c4a3fce0..3095abef7bbe3 100644 --- a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php +++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php @@ -95,6 +95,7 @@ public function testPrepareDataSource() 'title' => __('Delete %1', $title), 'message' => __('Are you sure you want to delete a %1 record?', $title) ], + 'post' => true ] ], ] diff --git a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php index b0cc1bf061a48..9b3165a2c5517 100644 --- a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php +++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php @@ -70,6 +70,7 @@ public function testPrepareItemsByPageId() 'title' => __('Delete %1', $title), 'message' => __('Are you sure you want to delete a %1 record?', $title) ], + 'post' => true ] ], ] diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php index 60b9f34d29ae6..f68ef35e534f3 100644 --- a/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php @@ -55,10 +55,7 @@ public function __construct( } /** - * Prepare Data Source - * - * @param array $dataSource - * @return array + * @inheritDoc */ public function prepareDataSource(array $dataSource) { @@ -87,7 +84,8 @@ public function prepareDataSource(array $dataSource) 'confirm' => [ 'title' => __('Delete %1', $title), 'message' => __('Are you sure you want to delete a %1 record?', $title) - ] + ], + 'post' => true ] ]; } @@ -99,6 +97,7 @@ public function prepareDataSource(array $dataSource) /** * Get instance of escaper + * * @return Escaper * @deprecated 101.0.7 */ diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php index ea6882e21c85f..26d31456bf61d 100644 --- a/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php +++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php @@ -67,10 +67,7 @@ public function __construct( } /** - * Prepare Data Source - * - * @param array $dataSource - * @return array + * @inheritDoc */ public function prepareDataSource(array $dataSource) { @@ -89,7 +86,8 @@ public function prepareDataSource(array $dataSource) 'confirm' => [ 'title' => __('Delete %1', $title), 'message' => __('Are you sure you want to delete a %1 record?', $title) - ] + ], + 'post' => true ]; } if (isset($item['identifier'])) { @@ -110,6 +108,7 @@ public function prepareDataSource(array $dataSource) /** * Get instance of escaper + * * @return Escaper * @deprecated 101.0.7 */ From ade72ffadf747b9e19edae9473e982d43100e082 Mon Sep 17 00:00:00 2001 From: Hwashiang Yu <hwyu@adobe.com> Date: Wed, 19 Sep 2018 10:16:13 -0500 Subject: [PATCH 080/118] MC-3857: Products Content Type is broken on Dynamic Block page - Added block creation on failed blocked retrieval in product list --- .../Magento/CatalogWidget/Block/Product/ProductsList.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index 9a55f981b7607..14bcc3956334d 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -198,6 +198,13 @@ public function getProductPriceHtml( /** @var \Magento\Framework\Pricing\Render $priceRender */ $priceRender = $this->getLayout()->getBlock('product.price.render.default'); + if (!$priceRender) { + $priceRender = $this->getLayout()->createBlock( + \Magento\Framework\Pricing\Render::class, + 'product.price.render.default', + ['data' => ['price_render_handle' => 'catalog_product_prices']] + ); + } $price = ''; if ($priceRender) { From 681654ccc7ccaa8b003a0dc8336da3e087b0b443 Mon Sep 17 00:00:00 2001 From: Hwashiang Yu <hwyu@adobe.com> Date: Thu, 20 Sep 2018 10:14:01 -0500 Subject: [PATCH 081/118] MC-3857: Products Content Type is broken on Dynamic Block page - Removed uneeded conditional from producslist.php --- .../CatalogWidget/Block/Product/ProductsList.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index 14bcc3956334d..31edeaae9daba 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -206,14 +206,12 @@ public function getProductPriceHtml( ); } - $price = ''; - if ($priceRender) { - $price = $priceRender->render( - \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE, - $product, - $arguments - ); - } + $price = $priceRender->render( + \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE, + $product, + $arguments + ); + return $price; } From f02eb037a9fe250e3545469a9d412a1f37fa1c21 Mon Sep 17 00:00:00 2001 From: Hwashiang Yu <hwyu@adobe.com> Date: Mon, 17 Sep 2018 15:20:05 -0500 Subject: [PATCH 082/118] MC-4114: There is a modal overlay display on Schedule Update page when trying to add a block using Block Content Type - Removed conditional from _unsetActive to allow overlay z-index to decrease on multiple layers of modal --- app/code/Magento/Ui/view/base/web/js/modal/modal.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal.js b/app/code/Magento/Ui/view/base/web/js/modal/modal.js index f016b0dbefd87..c81274337f418 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/modal.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal.js @@ -363,14 +363,7 @@ define([ this.modal.data('active', false); if (this.overlay) { - // In cases when one modal is closed but there is another modal open (e.g. admin notifications) - // to avoid collisions between overlay and modal zIndexes - // overlay zIndex is set to be less than modal one - if (this._getVisibleCount() === 1) { - this.overlay.zIndex(this.prevOverlayIndex - 1); - } else { - this.overlay.zIndex(this.prevOverlayIndex); - } + this.overlay.zIndex(this.prevOverlayIndex - 1); } }, From bcd54542e7812deae7b7ada493d8c96c8853d7fb Mon Sep 17 00:00:00 2001 From: Max Lesechko <mlesechko@magento.com> Date: Wed, 3 Oct 2018 15:54:16 -0500 Subject: [PATCH 083/118] MC-4303: Functional tests failure with the installed Dotmailer module --- .../Mftf/Section/BraintreeConfigurationPaymentSection.xml | 1 + .../Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml index d8e1b837a1d1b..d9f2b14a40e2f 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <section name="BraintreeConfigurationPaymentSection"> <element name="creditCart" type="radio" selector="#braintree"/> + <element name="paymentMethodContainer" type="block" selector=".payment-method-braintree"/> <element name="paymentMethod" type="radio" selector="//div[@class='payment-group']//input[contains(@id, 'braintree_cc_vault_')]"/> <element name="cartFrame" type="iframe" selector="braintree-hosted-field-number"/> <element name="monthFrame" type="iframe" selector="braintree-hosted-field-expirationMonth"/> diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml index 7f6d862ada085..114c79189101a 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml @@ -61,10 +61,12 @@ <!--Fill cart data--> <click selector="{{BraintreeConfigurationPaymentSection.creditCart}}" stepKey="SelectBraintreePaymentMethod"/> <waitForPageLoad stepKey="waitForPageLoad3"/> + <scrollTo selector="{{BraintreeConfigurationPaymentSection.creditCart}}" stepKey="ScrollToCreditCardSection"/> <actionGroup ref="StorefrontFillCartDataActionGroup" stepKey="StorefrontFillCartDataActionGroup"/> <waitForPageLoad stepKey="waitForPageLoad4"/> <!--Place order--> - <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="PlaceOrder"/> + <click selector="{{BraintreeConfigurationPaymentSection.paymentMethodContainer}} {{CheckoutPaymentSection.placeOrder}}" + stepKey="PlaceOrder"/> <waitForPageLoad stepKey="waitForPageLoad5"/> <!--Add product to cart again--> From d18a0bffd2a2b81bfb65705e1909f0a9bced5a7e Mon Sep 17 00:00:00 2001 From: Alex Paliarush <paliarus@adobe.com> Date: Wed, 3 Oct 2018 20:28:18 -0500 Subject: [PATCH 084/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization - Optimized media gallery and product options loading --- .../Magento/Catalog/Model/Product/Media/Config.php | 10 +++++++++- .../Model/Resolver/Products/DataProvider/Product.php | 8 ++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Media/Config.php b/app/code/Magento/Catalog/Model/Product/Media/Config.php index 72936d317399c..b01f254b8377b 100644 --- a/app/code/Magento/Catalog/Model/Product/Media/Config.php +++ b/app/code/Magento/Catalog/Model/Product/Media/Config.php @@ -31,6 +31,11 @@ class Config implements ConfigInterface */ private $attributeHelper; + /** + * @var string[] + */ + private $mediaAttributeCodes; + /** * @param StoreManagerInterface $storeManager */ @@ -173,7 +178,10 @@ protected function _prepareFile($file) */ public function getMediaAttributeCodes() { - return $this->getAttributeHelper()->getAttributeCodesByFrontendType('media_image'); + if (!isset($this->mediaAttributeCodes)) { + $this->mediaAttributeCodes = $this->getAttributeHelper()->getAttributeCodesByFrontendType('media_image'); + } + return $this->mediaAttributeCodes; } /** diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php index 2c73d7a079170..7f1fd71942253 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php @@ -86,8 +86,12 @@ public function getList( $collection->load(); // Methods that perform extra fetches post-load - $collection->addMediaGalleryData(); - $collection->addOptionsToResult(); + if (in_array('media_gallery_entries', $attributes)) { + $collection->addMediaGalleryData(); + } + if (in_array('options', $attributes)) { + $collection->addOptionsToResult(); + } $searchResult = $this->searchResultsFactory->create(); $searchResult->setSearchCriteria($searchCriteria); From e0e6de1e8c3f9cdfeec397a7f0c8e4c0f7eaec5b Mon Sep 17 00:00:00 2001 From: Alex Paliarush <paliarus@adobe.com> Date: Wed, 3 Oct 2018 21:34:05 -0500 Subject: [PATCH 085/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization - Optimized category data loading for products query --- .../CatalogGraphQl/Model/AttributesJoiner.php | 37 +++++++++++++++---- .../Model/Resolver/Categories.php | 12 ++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/AttributesJoiner.php b/app/code/Magento/CatalogGraphQl/Model/AttributesJoiner.php index ebd8671de02fb..d57154c429920 100644 --- a/app/code/Magento/CatalogGraphQl/Model/AttributesJoiner.php +++ b/app/code/Magento/CatalogGraphQl/Model/AttributesJoiner.php @@ -15,6 +15,11 @@ */ class AttributesJoiner { + /** + * @var array + */ + private $queryFields = []; + /** * Join fields attached to field node to collection's select. * @@ -24,17 +29,33 @@ class AttributesJoiner */ public function join(FieldNode $fieldNode, AbstractCollection $collection) : void { - $query = $fieldNode->selectionSet->selections; - - /** @var FieldNode $field */ - foreach ($query as $field) { - if ($field->kind === 'InlineFragment') { - continue; + foreach ($this->getQueryFields($fieldNode) as $field) { + if (!$collection->isAttributeAdded($field)) { + $collection->addAttributeToSelect($field); } + } + } - if (!$collection->isAttributeAdded($field->name->value)) { - $collection->addAttributeToSelect($field->name->value); + /** + * Get an array of queried fields. + * + * @param FieldNode $fieldNode + * @return string[] + */ + public function getQueryFields(FieldNode $fieldNode) + { + if (!isset($this->queryFields[$fieldNode->name->value])) { + $this->queryFields[$fieldNode->name->value] = []; + $query = $fieldNode->selectionSet->selections; + /** @var FieldNode $field */ + foreach ($query as $field) { + if ($field->kind === 'InlineFragment') { + continue; + } + $this->queryFields[$fieldNode->name->value][] = $field->name->value; } } + + return $this->queryFields[$fieldNode->name->value]; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php index 4326a51f309b1..11614e79bba22 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php @@ -107,6 +107,18 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value /** @var CategoryInterface | \Magento\Catalog\Model\Category $item */ foreach ($this->collection as $item) { if (in_array($item->getId(), $categoryIds)) { + + // Try to extract all requested fields from the loaded collection data + $categories[$item->getId()] = $item->getData(); + $categories[$item->getId()]['id'] = $item->getId(); + $requestedFields = $that->attributesJoiner->getQueryFields($info->fieldNodes[0]); + $extractedFields = array_keys($categories[$item->getId()]); + $foundFields = array_intersect($requestedFields, $extractedFields); + if (count($requestedFields) === count($foundFields)) { + continue; + } + + // If not all requested fields were extracted from the collection, start more complex extraction $categories[$item->getId()] = $this->dataObjectProcessor->buildOutputDataArray( $item, CategoryInterface::class From 1e3728050a4236827bf65a52fd1dfc8e759d1c59 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun <ogorkun@magento.com> Date: Thu, 4 Oct 2018 10:24:24 +0300 Subject: [PATCH 086/118] MAGETWO-88654: Sales Rule Widget Label --- .../SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php b/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php index b4be904223aac..901866d52f73f 100644 --- a/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php +++ b/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php @@ -3,8 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\SalesRule\Block\Adminhtml\Promo\Widget; +/** + * Widget that allows to select a sales rule. + */ class Chooser extends \Magento\Backend\Block\Widget\Grid\Extended { /** @@ -87,7 +91,7 @@ public function prepareElementHtml(\Magento\Framework\Data\Form\Element\Abstract if ($element->getValue()) { $rule = $this->ruleFactory->create()->load((int)$element->getValue()); if ($rule->getId()) { - $chooser->setLabel($rule->getName()); + $chooser->setLabel($this->escapeHtml($rule->getName())); } } From b6dcb9f71084aca48488ff070fd03ec30157ac70 Mon Sep 17 00:00:00 2001 From: Dave Macaulay <dmacaulay@magento.com> Date: Thu, 4 Oct 2018 12:01:16 +0200 Subject: [PATCH 087/118] MC-4014: PageBuilder Performance Is Bad With Minimal Content - Update dom-observer to allow for certain nodes to be ignored --- .../web/js/lib/view/utils/dom-observer.js | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js index 4590af4f2d635..03012918f4a0d 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js @@ -12,7 +12,8 @@ define([ var counter = 1, watchers, - globalObserver; + globalObserver, + disabledNodes = []; watchers = { selectors: {}, @@ -238,11 +239,58 @@ define([ }; } + /** + * Verify if the DOM node is a child of a defined disabled node, if so we shouldn't observe provided mutation. + * + * @param {Object} mutation - a single mutation + * @returns {Boolean} + */ + function shouldObserveMutation(mutation) { + var isDisabled; + + if (disabledNodes.length > 0) { + // Iterate through the disabled nodes and determine if this mutation is occurring inside one of them + isDisabled = _.find(disabledNodes, function (node) { + return node === mutation.target || $.contains(node, mutation.target); + }); + + // If we find a matching node we should not observe the mutation + return !isDisabled; + } + + return true; + } + + /** + * Should we observe these mutations? Check the first and last mutation to determine if this is a disabled mutation, + * we check both the first and last in case one has been removed from the DOM during the process of the mutation. + * + * @param {Array} mutations - An array of mutation records. + * @returns {Boolean} + */ + function shouldObserveMutations(mutations) { + var firstMutation, + lastMutation; + + if (mutations.length > 0) { + firstMutation = mutations[0]; + lastMutation = mutations[mutations.length - 1]; + + return shouldObserveMutation(firstMutation) && shouldObserveMutation(lastMutation); + } + + return true; + } + globalObserver = new MutationObserver(function (mutations) { - var changes = formChangesLists(mutations); + var changes; + + if (shouldObserveMutations(mutations)) { + changes = formChangesLists(mutations); - changes.removed.forEach(processRemoved); - changes.added.forEach(processAdded); + changes.removed.forEach(processRemoved); + changes.added.forEach(processAdded); + } }); globalObserver.observe(document.body, { @@ -251,6 +299,16 @@ define([ }); return { + /** + * Disable a node from being observed by the mutations, you may want to disable specific aspects of the + * application which are heavy on DOM changes. The observer running on some actions could cause significant + * delays and degrade the performance of that specific part of the application exponentially. + * + * @param {HTMLElement} node - a HTML node within the document + */ + disableNode: function (node) { + disabledNodes.push(node); + }, /** * Adds listener for the appearance of nodes that matches provided From 420ab7ef10211a2e1664d55b8445f3c39659643c Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov <dvoskoboinikov@magento.com> Date: Thu, 4 Oct 2018 14:00:02 +0300 Subject: [PATCH 088/118] MAGETWO-91699: Displaying of error messages in a customer account is broken --- .../Customer/Controller/Account/EditPost.php | 17 +++++++++++++---- .../Magento/Customer/Controller/AccountTest.php | 6 +++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Account/EditPost.php b/app/code/Magento/Customer/Controller/Account/EditPost.php index e3b3d8345224e..38bc52eac4266 100644 --- a/app/code/Magento/Customer/Controller/Account/EditPost.php +++ b/app/code/Magento/Customer/Controller/Account/EditPost.php @@ -22,6 +22,7 @@ use Magento\Customer\Model\CustomerExtractor; use Magento\Customer\Model\Session; use Magento\Framework\App\Action\Context; +use Magento\Framework\Escaper; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\InvalidEmailOrPasswordException; use Magento\Framework\Exception\State\UserLockedException; @@ -79,6 +80,11 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http */ private $customerMapper; + /** + * @var Escaper + */ + private $escaper; + /** * @param Context $context * @param Session $customerSession @@ -86,6 +92,7 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http * @param CustomerRepositoryInterface $customerRepository * @param Validator $formKeyValidator * @param CustomerExtractor $customerExtractor + * @param Escaper|null $escaper */ public function __construct( Context $context, @@ -93,7 +100,8 @@ public function __construct( AccountManagementInterface $customerAccountManagement, CustomerRepositoryInterface $customerRepository, Validator $formKeyValidator, - CustomerExtractor $customerExtractor + CustomerExtractor $customerExtractor, + ?Escaper $escaper = null ) { parent::__construct($context); $this->session = $customerSession; @@ -101,6 +109,7 @@ public function __construct( $this->customerRepository = $customerRepository; $this->formKeyValidator = $formKeyValidator; $this->customerExtractor = $customerExtractor; + $this->escaper = $escaper ?: ObjectManager::getInstance()->get(Escaper::class); } /** @@ -196,7 +205,7 @@ public function execute() $this->messageManager->addSuccess(__('You saved the account information.')); return $resultRedirect->setPath('customer/account'); } catch (InvalidEmailOrPasswordException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($e->getMessage())); } catch (UserLockedException $e) { $message = __( 'The account sign-in was incorrect or your account is disabled temporarily. ' @@ -207,9 +216,9 @@ public function execute() $this->messageManager->addError($message); return $resultRedirect->setPath('customer/account/login'); } catch (InputException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($e->getMessage())); foreach ($e->getErrors() as $error) { - $this->messageManager->addError($error->getMessage()); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($error->getMessage())); } } catch (\Magento\Framework\Exception\LocalizedException $e) { $this->messageManager->addError($e->getMessage()); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index 921fa81fa6f23..eb06d8d5d66bf 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -606,7 +606,7 @@ public function testMissingDataEditPostAction() $this->assertRedirect($this->stringContains('customer/account/edit/')); $this->assertSessionMessages( - $this->equalTo(['"Email" is not a valid email address.']), + $this->equalTo(['"Email" is not a valid email address.']), MessageInterface::TYPE_ERROR ); } @@ -637,7 +637,7 @@ public function testWrongPasswordEditPostAction() $this->assertRedirect($this->stringContains('customer/account/edit/')); // Not sure if its the most secure message. Not changing the behavior for now in the new AccountManagement APIs. $this->assertSessionMessages( - $this->equalTo(["The password doesn't match this account. Verify the password and try again."]), + $this->equalTo(["The password doesn't match this account. Verify the password and try again."]), MessageInterface::TYPE_ERROR ); } @@ -665,7 +665,7 @@ public function testWrongConfirmationEditPostAction() $this->assertRedirect($this->stringContains('customer/account/edit/')); $this->assertSessionMessages( - $this->equalTo(['Password confirmation doesn\'t match entered password.']), + $this->equalTo(['Password confirmation doesn't match entered password.']), MessageInterface::TYPE_ERROR ); } From 694d2191c74b3ecba27748c11380ee6a70cd3117 Mon Sep 17 00:00:00 2001 From: Volodymyr Kublytskyi <vkublytskyi@magento.com> Date: Wed, 3 Oct 2018 12:47:18 +0300 Subject: [PATCH 089/118] Fix doc block style --- .../Controller/Rest/Asynchronous/InputParamsResolver.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php b/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php index 4ebb23f33e97b..cb72189f6d5c2 100644 --- a/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php +++ b/app/code/Magento/WebapiAsync/Controller/Rest/Asynchronous/InputParamsResolver.php @@ -80,12 +80,14 @@ public function __construct( /** * Process and resolve input parameters + * * Return array with validated input params * or throw \Exception if at least one request entity params is not valid * * @return array * @throws \Magento\Framework\Exception\InputException if no value is provided for required parameters * @throws \Magento\Framework\Webapi\Exception + * @throws \Magento\Framework\Exception\AuthorizationException */ public function resolve() { @@ -110,6 +112,8 @@ public function resolve() } /** + * Detect route by input parameters + * * @return \Magento\Webapi\Controller\Rest\Router\Route */ public function getRoute() @@ -118,9 +122,10 @@ public function getRoute() } /** + * Resolve parameters for service + * * Convert the input array from key-value format to a list of parameters * suitable for the specified class / method. - * * Instead of \Magento\Webapi\Controller\Rest\InputParamsResolver * we don't need to merge body params with url params and use only body params * From 12f668cb28dfc9f657563bb21016bd3ea0c0cee1 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 4 Oct 2018 10:02:42 -0500 Subject: [PATCH 090/118] MAGETWO-93001: AvoidIdSniff Static test rule gives a false positive result - Changed implementation of sniff to look for selectors and ignore all else --- .../Magento/Sniffs/Less/AvoidIdSniff.php | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php b/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php index f9cec6404dc69..e6e747aed3262 100644 --- a/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php @@ -14,7 +14,6 @@ * Ensure that id selector is not used * * @link http://devdocs.magento.com/guides/v2.0/coding-standards/code-standard-less.html#types - * */ class AvoidIdSniff implements Sniff { @@ -26,15 +25,7 @@ class AvoidIdSniff implements Sniff public $supportedTokenizers = [TokenizerSymbolsInterface::TOKENIZER_CSS]; /** - * @var array - */ - private $symbolsBeforeId = [ - TokenizerSymbolsInterface::INDENT_SPACES, - TokenizerSymbolsInterface::NEW_LINE, - ]; - - /** - * {@inheritdoc} + * @inheritdoc */ public function register() { @@ -42,15 +33,56 @@ public function register() } /** - * {@inheritdoc} + * Will flag any selector that looks like the following: + * #foo[bar], + * #foo[bar=bash], + * #foo[bar~=bash], + * #foo[bar$=bash], + * #foo[bar*=bash], + * #foo[bar='bash'], + * #foo:hover, + * #foo:nth-last-of-type(n), + * #foo::before, + * #foo + div, + * #foo > div, + * #foo ~ div, + * #foo\3Abar ~ div, + * #foo\:bar ~ div, + * div#foo { + * blah: 'abc'; + * } + * + * @inheritdoc */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - if (T_WHITESPACE === $tokens[$stackPtr - 1]['code'] - && in_array($tokens[$stackPtr - 1]['content'], $this->symbolsBeforeId) - ) { + $nextToken = $phpcsFile->findNext([ + T_HASH, + T_WHITESPACE, + T_STRING_CONCAT, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET, + T_DOUBLE_QUOTED_STRING, + T_CONSTANT_ENCAPSED_STRING, + T_DOUBLE_COLON, + T_COLON, + T_EQUAL, + T_MUL_EQUAL, + T_STRING, + T_NONE, + T_DOLLAR, + T_GREATER_THAN, + T_PLUS, + T_NS_SEPARATOR, + T_LNUMBER, + ], $stackPtr + 1, null, true); + + // Anything except a { or a , means this is not a selector + if (in_array($tokens[$nextToken]['code'], [T_OPEN_CURLY_BRACKET, T_COMMA])) { $phpcsFile->addError('Id selector is used', $stackPtr, 'IdSelectorUsage'); } } From ae9f00c4ace79710fe87da37874102a73e1f5d6e Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 4 Oct 2018 10:10:55 -0500 Subject: [PATCH 091/118] MAGETWO-93001: AvoidIdSniff Static test rule gives a false positive result - Added additional selector support and more doc --- .../static/framework/Magento/Sniffs/Less/AvoidIdSniff.php | 3 +++ dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php b/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php index e6e747aed3262..f12e2dba6e447 100644 --- a/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php @@ -39,6 +39,7 @@ public function register() * #foo[bar~=bash], * #foo[bar$=bash], * #foo[bar*=bash], + * #foo[bar|=bash], * #foo[bar='bash'], * #foo:hover, * #foo:nth-last-of-type(n), @@ -48,6 +49,7 @@ public function register() * #foo ~ div, * #foo\3Abar ~ div, * #foo\:bar ~ div, + * #foo.bar .baz, * div#foo { * blah: 'abc'; * } @@ -72,6 +74,7 @@ public function process(File $phpcsFile, $stackPtr) T_COLON, T_EQUAL, T_MUL_EQUAL, + T_OR_EQUAL, T_STRING, T_NONE, T_DOLLAR, diff --git a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php index 47d5df331e5cd..82bb2526a9e4a 100644 --- a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php @@ -52,7 +52,7 @@ public function testCodeStyle() $codeSniffer->setExtensions([LessWrapper::LESS_FILE_EXTENSION]); - $fileList = PHPCodeTest::getWhitelist([LessWrapper::LESS_FILE_EXTENSION], __DIR__, __DIR__); + $fileList = ['/Users/nathsmit/Sites/pagebuilder/app/myfile.less'];//PHPCodeTest::getWhitelist([LessWrapper::LESS_FILE_EXTENSION], __DIR__, __DIR__); $result = $codeSniffer->run($this->filterFiles($fileList)); From a2d2eb3cd14739ac1c9959be237eaaf3a357853d Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 4 Oct 2018 10:11:59 -0500 Subject: [PATCH 092/118] MAGETWO-93001: AvoidIdSniff Static test rule gives a false positive result - Removed test data --- dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php index 82bb2526a9e4a..47d5df331e5cd 100644 --- a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php @@ -52,7 +52,7 @@ public function testCodeStyle() $codeSniffer->setExtensions([LessWrapper::LESS_FILE_EXTENSION]); - $fileList = ['/Users/nathsmit/Sites/pagebuilder/app/myfile.less'];//PHPCodeTest::getWhitelist([LessWrapper::LESS_FILE_EXTENSION], __DIR__, __DIR__); + $fileList = PHPCodeTest::getWhitelist([LessWrapper::LESS_FILE_EXTENSION], __DIR__, __DIR__); $result = $codeSniffer->run($this->filterFiles($fileList)); From 42c46c1730a1ada0a19bcf31a4a0271d47c096d8 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 4 Oct 2018 11:11:48 -0500 Subject: [PATCH 093/118] MAGETWO-87353: \Magento\Cms\Model\BlockTest::testUpdateTime randomly fails on CI - Changed test to only use timestamps from the database for comparison --- .../testsuite/Magento/Cms/Model/BlockTest.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php index 16331ccde245c..3925975a0f70e 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php @@ -7,6 +7,7 @@ use Magento\Cms\Model\ResourceModel\Block; use Magento\Cms\Model\BlockFactory; +use Magento\Framework\App\ResourceConnection; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Stdlib\DateTime\DateTime; use Magento\Framework\Stdlib\DateTime\Timezone; @@ -82,23 +83,26 @@ public function testGetByIdentifier(array $blockData) */ public function testUpdateTime(array $blockData) { + /** + * @var $db \Magento\Framework\DB\Adapter\AdapterInterface + */ + $db = $this->objectManager->get(\Magento\Framework\App\ResourceConnection::class) + ->getConnection(ResourceConnection::DEFAULT_CONNECTION); # Prepare and save the temporary block - $beforeTimestamp = $this->objectManager->get(DateTime::class)->timestamp(); $tempBlock = $this->blockFactory->create(); $tempBlock->setData($blockData); + $beforeTimestamp = $db->fetchCol('SELECT UNIX_TIMESTAMP()')[0]; $this->blockResource->save($tempBlock); + $afterTimestamp = $db->fetchCol('SELECT UNIX_TIMESTAMP()')[0]; # Load previously created block and compare identifiers $storeId = reset($blockData['stores']); $block = $this->blockIdentifier->execute($blockData['identifier'], $storeId); - $afterTimestamp = $this->objectManager->get(DateTime::class)->timestamp(); $blockTimestamp = strtotime($block->getUpdateTime()); /* - * This test used to fail due to a race condition @see MAGETWO-87353 - * The DB time would be one second older than the check time. The new check allows the DB time - * to be between the test start time and right before the assertion. + * These checks prevent a race condition MAGETWO-87353 */ $this->assertGreaterThanOrEqual($beforeTimestamp, $blockTimestamp); $this->assertLessThanOrEqual($afterTimestamp, $blockTimestamp); From 459834557562947a9959d0486ad6f695b8d79433 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 4 Oct 2018 12:49:49 -0500 Subject: [PATCH 094/118] MAGETWO-93001: AvoidIdSniff Static test rule gives a false positive result - CR Feedback --- .../Magento/Sniffs/Less/AvoidIdSniff.php | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php b/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php index f12e2dba6e447..49339054f8766 100644 --- a/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/Less/AvoidIdSniff.php @@ -24,6 +24,35 @@ class AvoidIdSniff implements Sniff */ public $supportedTokenizers = [TokenizerSymbolsInterface::TOKENIZER_CSS]; + /** + * Tokens that can appear in a selector + * + * @var array + */ + private $selectorTokens = [ + T_HASH, + T_WHITESPACE, + T_STRING_CONCAT, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET, + T_DOUBLE_QUOTED_STRING, + T_CONSTANT_ENCAPSED_STRING, + T_DOUBLE_COLON, + T_COLON, + T_EQUAL, + T_MUL_EQUAL, + T_OR_EQUAL, + T_STRING, + T_NONE, + T_DOLLAR, + T_GREATER_THAN, + T_PLUS, + T_NS_SEPARATOR, + T_LNUMBER, + ]; + /** * @inheritdoc */ @@ -33,6 +62,8 @@ public function register() } /** + * @inheritdoc + * * Will flag any selector that looks like the following: * #foo[bar], * #foo[bar=bash], @@ -53,39 +84,16 @@ public function register() * div#foo { * blah: 'abc'; * } - * - * @inheritdoc */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $nextToken = $phpcsFile->findNext([ - T_HASH, - T_WHITESPACE, - T_STRING_CONCAT, - T_OPEN_PARENTHESIS, - T_CLOSE_PARENTHESIS, - T_OPEN_SQUARE_BRACKET, - T_CLOSE_SQUARE_BRACKET, - T_DOUBLE_QUOTED_STRING, - T_CONSTANT_ENCAPSED_STRING, - T_DOUBLE_COLON, - T_COLON, - T_EQUAL, - T_MUL_EQUAL, - T_OR_EQUAL, - T_STRING, - T_NONE, - T_DOLLAR, - T_GREATER_THAN, - T_PLUS, - T_NS_SEPARATOR, - T_LNUMBER, - ], $stackPtr + 1, null, true); + // Find the next non-selector token + $nextToken = $phpcsFile->findNext($this->selectorTokens, $stackPtr + 1, null, true); // Anything except a { or a , means this is not a selector - if (in_array($tokens[$nextToken]['code'], [T_OPEN_CURLY_BRACKET, T_COMMA])) { + if ($nextToken !== false && in_array($tokens[$nextToken]['code'], [T_OPEN_CURLY_BRACKET, T_COMMA])) { $phpcsFile->addError('Id selector is used', $stackPtr, 'IdSelectorUsage'); } } From d1dfb8dfbfdf590b0786d040a4a05a1ee261a298 Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Thu, 13 Sep 2018 15:58:54 -0500 Subject: [PATCH 095/118] MAGETWO-89738: Sanity job failing on Bamboo PAT build --- .../Indexer/Price/CompositeProductRowSizeEstimatorTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimatorTest.php index 1c47644338143..728044b89cafe 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimatorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimatorTest.php @@ -49,7 +49,6 @@ protected function setUp() public function testEstimateRowSize() { - $this->markTestSkipped('Unskip after MAGETWO-89738'); $expectedResult = 40000000; $maxRelatedProductCount = 10; From 6facb56624b2d97bf4c5f793ed49a4d4e32eba7f Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Thu, 4 Oct 2018 14:51:05 -0500 Subject: [PATCH 096/118] MAGETWO-93001: AvoidIdSniff Static test rule gives a false positive result - Added unit test for sniff --- .../Magento/Sniffs/Less/AvoidIdSniffTest.php | 55 +++++++++++++++++++ .../Sniffs/Less/_files/avoid-ids-errors.txt | 26 +++++++++ .../Magento/Sniffs/Less/_files/avoid-ids.less | 34 ++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/AvoidIdSniffTest.php create mode 100644 dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt create mode 100644 dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/AvoidIdSniffTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/AvoidIdSniffTest.php new file mode 100644 index 0000000000000..ad9e8edd4d1b3 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/AvoidIdSniffTest.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Sniffs\Less; + +use Magento\TestFramework\CodingStandard\Tool\CodeSniffer\LessWrapper; + +class AvoidIdSniffTest extends \PHPUnit\Framework\TestCase +{ + /** + * @return array + */ + public function processDataProvider() + { + return [ + [ + 'avoid-ids.less', + 'avoid-ids-errors.txt' + ] + ]; + } + + /** + * @param string $fileUnderTest + * @param string $expectedReportFile + * @dataProvider processDataProvider + */ + public function testProcess($fileUnderTest, $expectedReportFile) + { + $reportFile = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'phpcs_report.txt'; + $wrapper = new LessWrapper(); + $codeSniffer = new \Magento\TestFramework\CodingStandard\Tool\CodeSniffer( + 'Magento', + $reportFile, + $wrapper + ); + $codeSniffer->setExtensions([LessWrapper::LESS_FILE_EXTENSION]); + $result = $codeSniffer->run( + [__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . $fileUnderTest] + ); + // Remove the absolute path to the file from the output + $actual = preg_replace('/^.+\n/', '', ltrim(file_get_contents($reportFile))); + $expected = file_get_contents( + __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . $expectedReportFile + ); + unlink($reportFile); + $this->assertEquals(1, $result); + $this->assertEquals($expected, $actual); + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt new file mode 100644 index 0000000000000..7ce7bc6de4ad0 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt @@ -0,0 +1,26 @@ +--------------------------------------------------------------------------------------------------------------------------------- +FOUND 20 ERRORS AFFECTING 20 LINES +--------------------------------------------------------------------------------------------------------------------------------- + 1 | ERROR | Id selector is used + 2 | ERROR | Id selector is used + 3 | ERROR | Id selector is used + 4 | ERROR | Id selector is used + 5 | ERROR | Id selector is used + 6 | ERROR | Id selector is used + 7 | ERROR | Id selector is used + 8 | ERROR | Id selector is used + 9 | ERROR | Id selector is used + 10 | ERROR | Id selector is used + 11 | ERROR | Id selector is used + 12 | ERROR | Id selector is used + 13 | ERROR | Id selector is used + 14 | ERROR | Id selector is used + 15 | ERROR | Id selector is used + 16 | ERROR | Id selector is used + 17 | ERROR | Id selector is used + 21 | ERROR | Id selector is used + 22 | ERROR | Id selector is used + 23 | ERROR | Id selector is used +--------------------------------------------------------------------------------------------------------------------------------- + + diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less new file mode 100644 index 0000000000000..45eb999c803c7 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less @@ -0,0 +1,34 @@ +#foo[bar], +#foo[bar=bash], +#foo[bar~=bash], +#foo[bar$=bash], +#foo[bar*=bash], +#foo[bar|=bash], +#foo[bar='bash'], +#foo:hover, +#foo:nth-last-of-type(n), +#foo::before, +#foo + div, +#foo > div, +#foo ~ div, +#foo\3Abar ~ div, +#foo\:bar ~ div, +#foo.bar .baz, +div#foo { + blah: 'abc'; +} + +.my #foo, +#foo .blah, +.my #foo .blah { + some: 'stuff'; +} +.blah { + #bar .baz(); + .foo #bar .baz(); + #bar .baz(); + + #bar .baz; + .foo #bar .baz; + #bar .baz; +} From 63887c28e24a36d9b5004d6258a42e8c79bb3fb0 Mon Sep 17 00:00:00 2001 From: Cari Spruiell <spruiell@adobe.com> Date: Fri, 5 Oct 2018 09:37:14 -0500 Subject: [PATCH 097/118] MC-3857: Products Content Type is broken on Dynamic Block page - fix static test failures --- .../Block/Product/ProductsList.php | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index 31edeaae9daba..8bec76428316b 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -14,7 +14,7 @@ /** * Catalog Products List widget block - * Class ProductsList + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ProductsList extends \Magento\Catalog\Block\Product\AbstractProduct implements BlockInterface, IdentityInterface @@ -130,7 +130,9 @@ public function __construct( } /** - * {@inheritdoc} + * Internal constructor, that is called from real constructor + * + * @return void */ protected function _construct() { @@ -174,7 +176,14 @@ public function getCacheKeyInfo() } /** - * {@inheritdoc} + * Return HTML block with tier price + * + * @param \Magento\Catalog\Model\Product $product + * @param string $priceType + * @param string $renderZone + * @param array $arguments + * @return string + * * @SuppressWarnings(PHPMD.NPathComplexity) */ public function getProductPriceHtml( @@ -216,6 +225,8 @@ public function getProductPriceHtml( } /** + * Before rendering html, but after trying to load cache + * * {@inheritdoc} */ protected function _beforeToHtml() @@ -254,6 +265,8 @@ public function createCollection() } /** + * Get conditions + * * @return \Magento\Rule\Model\Condition\Combine */ protected function getConditions() @@ -391,8 +404,9 @@ public function getTitle() } /** - * @return PriceCurrencyInterface + * Get currency of product * + * @return PriceCurrencyInterface * @deprecated 100.2.0 */ private function getPriceCurrency() From 8a3fd0440b7b54e8b51e171e81b26a812e14eed3 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 5 Oct 2018 10:09:16 -0500 Subject: [PATCH 098/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization - Optimized config elements initialization --- .../Products/Attributes/Collection.php | 3 + .../Magento/GraphQl/Controller/GraphQl.php | 10 +- .../Magento/Framework/GraphQl/Config.php | 11 +++ .../GraphQl/Config/Element/FieldFactory.php | 5 +- .../GraphQl/Query/FieldExtractor.php | 95 +++++++++++++++++++ 5 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php index ab0531ad09513..5218b055deec6 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php @@ -64,6 +64,9 @@ public function getAttributes() : AttributeCollection ['eq' => '1'] ] ); + $arrayOfAttributesRequested = \Magento\Framework\GraphQl\Query\FieldExtractor::$fieldsUsedInQuery; + //$this->collection->addFieldToFilter('attribute_code', ['eq' => 'cost1']); + //do a filter only by fields requested } return $this->collection->load(); diff --git a/app/code/Magento/GraphQl/Controller/GraphQl.php b/app/code/Magento/GraphQl/Controller/GraphQl.php index 493cabfaee922..f1c22465032fa 100644 --- a/app/code/Magento/GraphQl/Controller/GraphQl.php +++ b/app/code/Magento/GraphQl/Controller/GraphQl.php @@ -100,10 +100,18 @@ public function dispatch(RequestInterface $request) : ResponseInterface /** @var Http $request */ $this->requestProcessor->processHeaders($request); $data = $this->jsonSerializer->unserialize($request->getContent()); + + $source = isset($data['query']) ? $data['query'] : ''; + + $documentNode = \GraphQL\Language\Parser::parse(new \GraphQL\Language\Source($source ?: '', 'GraphQL')); + // We have to extract queried field names to avoid instantiation of non necessary fields in webonyx schema + // FieldExtractor class needs to be rewritten it was copied from \GraphQL\Language\Printer + \Magento\Framework\GraphQl\Query\FieldExtractor::doExtract($documentNode); + $schema = $this->schemaGenerator->generate(); $result = $this->queryProcessor->process( $schema, - isset($data['query']) ? $data['query'] : '', + $source, $this->resolverContext, isset($data['variables']) ? $data['variables'] : [] ); diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index 8d40d7fa6bb49..312da5cf0b8d5 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -53,6 +53,17 @@ public function getConfigElement(string $configElementName) : ConfigElementInter sprintf('Config element "%s" is not declared in GraphQL schema', $configElementName) ); } + + //limiting the data from config array that is cached + if (isset($data['fields'])) { + foreach ($data['fields'] as $fieldName => $fieldConfig) { + $arrayOfAttributesRequested = \Magento\Framework\GraphQl\Query\FieldExtractor::$fieldsUsedInQuery; + if (!isset($arrayOfAttributesRequested[$fieldName])) { + unset($data['fields'][$fieldName]); + } + } + } + return $this->configElementFactory->createFromConfigData($data); } diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldFactory.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldFactory.php index 1a022e92c829b..b9ec1dd87d122 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldFactory.php +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldFactory.php @@ -42,10 +42,11 @@ public function createFromConfigData( array $fieldData, array $arguments = [] ) : Field { - $arraySign = '/^.*(\[\])$/'; + $fieldType = $fieldData['type']; $isList = false; - if (preg_match($arraySign, $fieldData['type'])) { + //check if type ends with [] + if ($fieldType{strlen($fieldType) - 2} == '[' && $fieldType{strlen($fieldType) - 1} == ']') { $isList = true; $fieldData['type'] = str_replace('[]', '', $fieldData['type']); $fieldData['itemType'] = str_replace('[]', '', $fieldData['type']); diff --git a/lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php b/lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php new file mode 100644 index 0000000000000..429d03e93d1bb --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php @@ -0,0 +1,95 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\GraphQl\Query; + +use GraphQL\Language\AST\ArgumentNode; +use GraphQL\Language\AST\DirectiveDefinitionNode; +use GraphQL\Language\AST\EnumTypeDefinitionNode; +use GraphQL\Language\AST\EnumTypeExtensionNode; +use GraphQL\Language\AST\EnumValueDefinitionNode; +use GraphQL\Language\AST\FieldDefinitionNode; +use GraphQL\Language\AST\InputObjectTypeDefinitionNode; +use GraphQL\Language\AST\InputObjectTypeExtensionNode; +use GraphQL\Language\AST\InputValueDefinitionNode; +use GraphQL\Language\AST\InterfaceTypeDefinitionNode; +use GraphQL\Language\AST\InterfaceTypeExtensionNode; +use GraphQL\Language\AST\ListValueNode; +use GraphQL\Language\AST\BooleanValueNode; +use GraphQL\Language\AST\DirectiveNode; +use GraphQL\Language\AST\DocumentNode; +use GraphQL\Language\AST\EnumValueNode; +use GraphQL\Language\AST\FieldNode; +use GraphQL\Language\AST\FloatValueNode; +use GraphQL\Language\AST\FragmentDefinitionNode; +use GraphQL\Language\AST\FragmentSpreadNode; +use GraphQL\Language\AST\InlineFragmentNode; +use GraphQL\Language\AST\IntValueNode; +use GraphQL\Language\AST\ListTypeNode; +use GraphQL\Language\AST\NamedTypeNode; +use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\NodeKind; +use GraphQL\Language\AST\NonNullTypeNode; +use GraphQL\Language\AST\NullValueNode; +use GraphQL\Language\AST\ObjectFieldNode; +use GraphQL\Language\AST\ObjectTypeDefinitionNode; +use GraphQL\Language\AST\ObjectValueNode; +use GraphQL\Language\AST\OperationDefinitionNode; +use GraphQL\Language\AST\OperationTypeDefinitionNode; +use GraphQL\Language\AST\ScalarTypeDefinitionNode; +use GraphQL\Language\AST\ScalarTypeExtensionNode; +use GraphQL\Language\AST\SchemaDefinitionNode; +use GraphQL\Language\AST\SelectionSetNode; +use GraphQL\Language\AST\StringValueNode; +use GraphQL\Language\AST\ObjectTypeExtensionNode; +use GraphQL\Language\AST\UnionTypeDefinitionNode; +use GraphQL\Language\AST\UnionTypeExtensionNode; +use GraphQL\Language\AST\VariableDefinitionNode; +use GraphQL\Utils\Utils; + +/** + * Prints AST to string. Capable of printing GraphQL queries and Type definition language. + * Useful for pretty-printing queries or printing back AST for logging, documentation, etc. + * + * Usage example: + * + * ```php + * $query = 'query myQuery {someField}'; + * $ast = GraphQL\Language\Parser::parse($query); + * $printed = GraphQL\Language\Printer::doPrint($ast); + * ``` + * This class was copied from \GraphQL\Language\Printer + */ +class FieldExtractor +{ + + public static $fieldsUsedInQuery = []; + /** + * Prints AST to string. Capable of printing GraphQL queries and Type definition language. + * + * @api + * @param Node $ast + * @return string + */ + public static function doExtract($ast) + { + static $instance; + $instance = $instance ?: new static(); + return $instance->extract($ast); + } + + public function extract($ast) + { + return \GraphQL\Language\Visitor::visit($ast, [ + 'leave' => [ + NodeKind::NAME => function(Node $node) { + self::$fieldsUsedInQuery[$node->value] = $node->value; + } + ] + ]); + } +} From 57ff992b89e2347282af46ee1e77f122abba86a4 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Fri, 5 Oct 2018 11:35:28 -0500 Subject: [PATCH 099/118] MAGETWO-95346: Configurable and Bundled Product InvoiceOrder Api Service - Fixed bug and added tests --- .../Sales/Model/Service/InvoiceService.php | 6 +- .../Service/V1/OrderInvoiceCreateTest.php | 88 +++++++++++++++++++ .../Sales/_files/order_with_bundle.php | 84 ++++++++++++++++++ .../_files/order_with_bundle_rollback.php | 8 ++ 4 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php index 718f55c3e551c..fa2dcff191775 100644 --- a/app/code/Magento/Sales/Model/Service/InvoiceService.php +++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php @@ -136,7 +136,7 @@ public function prepareInvoice(Order $order, array $qtys = []) $totalQty = 0; $qtys = $this->prepareItemsQty($order, $qtys); foreach ($order->getAllItems() as $orderItem) { - if (!$this->_canInvoiceItem($orderItem)) { + if (!$this->_canInvoiceItem($orderItem, $qtys)) { continue; } $item = $this->orderConverter->itemToInvoiceItem($orderItem); @@ -196,12 +196,12 @@ private function prepareItemsQty(Order $order, array $qtys = []) * with parent item which is included to invoice * * @param \Magento\Sales\Api\Data\OrderItemInterface $item + * @param array $qtys * @return bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - protected function _canInvoiceItem(\Magento\Sales\Api\Data\OrderItemInterface $item) + protected function _canInvoiceItem(\Magento\Sales\Api\Data\OrderItemInterface $item, array $qtys = []) { - $qtys = []; if ($item->getLockedDoInvoice()) { return false; } diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php index 49e05832f2ef3..941421d456ca9 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php @@ -90,4 +90,92 @@ public function testInvoiceCreate() 'Failed asserting that Order status was changed' ); } + + /** + * Tests that MAGETWO-95346 was fixed for bundled products + * + * @expectedException \Exception + * @codingStandardsIgnoreStart + * @expectedExceptionMessage {"message":"Invoice Document Validation Error(s):\nThe invoice can't be created without products. Add products and try again."} + * @codingStandardsIgnoreEnd + * @magentoApiDataFixture Magento/Sales/_files/order_with_bundle.php + */ + public function testOrderWithBundleInvoicedWithInvalidQuantitiesReturnsError() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/invoice', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'execute', + ], + ]; + + $requestData = [ + 'notify' => true, + 'appendComment' => true, + 'items' => [ + [ + 'order_item_id' => -1, + 'qty' => 1 + ] + ], + 'comment' => [ + 'comment' => 'Test offline', + ], + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * Tests that MAGETWO-95346 was fixed for configurable products + * + * @expectedException \Exception + * @codingStandardsIgnoreStart + * @expectedExceptionMessage {"message":"Invoice Document Validation Error(s):\nThe invoice can't be created without products. Add products and try again."} + * @codingStandardsIgnoreEnd + * @magentoApiDataFixture Magento/Sales/_files/order_configurable_product.php + */ + public function testOrderWithConfigurableProductInvoicedWithInvalidQuantitiesReturnsError() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/invoice', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'execute', + ], + ]; + + $requestData = [ + 'notify' => true, + 'appendComment' => true, + 'items' => [ + [ + 'order_item_id' => -1, + 'qty' => 1 + ] + ], + 'comment' => [ + 'comment' => 'Test offline', + ], + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php new file mode 100644 index 0000000000000..6b6d6d6e6ec04 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\Sales\Api\OrderItemRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Item; +use Magento\TestFramework\ObjectManager; + +$objectManager = ObjectManager::getInstance(); + +require 'order.php'; +/** @var Order $order */ + +$orderItems = [ + [ + OrderItemInterface::PRODUCT_ID => 2, + OrderItemInterface::BASE_PRICE => 100, + OrderItemInterface::ORDER_ID => $order->getId(), + OrderItemInterface::QTY_ORDERED => 2, + OrderItemInterface::QTY_INVOICED => 2, + OrderItemInterface::PRICE => 100, + OrderItemInterface::ROW_TOTAL => 102, + OrderItemInterface::PRODUCT_TYPE => 'bundle', + 'product_options' => [ + 'product_calculations' => 0, + ], + 'children' => [ + [ + OrderItemInterface::PRODUCT_ID => 13, + OrderItemInterface::ORDER_ID => $order->getId(), + OrderItemInterface::QTY_ORDERED => 10, + OrderItemInterface::QTY_INVOICED => 10, + OrderItemInterface::BASE_PRICE => 90, + OrderItemInterface::PRICE => 90, + OrderItemInterface::ROW_TOTAL => 92, + OrderItemInterface::PRODUCT_TYPE => 'simple', + 'product_options' => [ + 'bundle_selection_attributes' => [ + 'qty' => 2, + ], + ], + ], + ], + ], +]; + +if (!function_exists('saveOrderItems')) { + /** + * Save Order Items. + * + * @param array $orderItems + * @param Item|null $parentOrderItem [optional] + * @return void + */ + function saveOrderItems(array $orderItems, Order $order, $parentOrderItem = null) + { + $objectManager = ObjectManager::getInstance(); + + foreach ($orderItems as $orderItemData) { + /** @var Item $orderItem */ + $orderItem = $objectManager->create(Item::class); + if (null !== $parentOrderItem) { + $orderItemData['parent_item'] = $parentOrderItem; + } + $orderItem->setData($orderItemData); + $order->addItem($orderItem); + + if (isset($orderItemData['children'])) { + saveOrderItems($orderItemData['children'], $order, $orderItem); + } + } + } +} + +saveOrderItems($orderItems, $order); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$order = $orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php new file mode 100644 index 0000000000000..dd52deab825cb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +require 'order_rollback.php'; From b6ff09014c1fead6f6e8c0a3020e2a4ab94a3812 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Fri, 5 Oct 2018 11:50:43 -0500 Subject: [PATCH 100/118] MAGETWO-93001: AvoidIdSniff Static test rule gives a false positive result - Fixed copyright header static failure --- .../Magento/Sniffs/Less/_files/avoid-ids-errors.txt | 12 ++++++------ .../Magento/Sniffs/Less/_files/avoid-ids.less | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt index 7ce7bc6de4ad0..ebc01c4e0852e 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids-errors.txt @@ -1,11 +1,6 @@ --------------------------------------------------------------------------------------------------------------------------------- FOUND 20 ERRORS AFFECTING 20 LINES --------------------------------------------------------------------------------------------------------------------------------- - 1 | ERROR | Id selector is used - 2 | ERROR | Id selector is used - 3 | ERROR | Id selector is used - 4 | ERROR | Id selector is used - 5 | ERROR | Id selector is used 6 | ERROR | Id selector is used 7 | ERROR | Id selector is used 8 | ERROR | Id selector is used @@ -18,9 +13,14 @@ FOUND 20 ERRORS AFFECTING 20 LINES 15 | ERROR | Id selector is used 16 | ERROR | Id selector is used 17 | ERROR | Id selector is used + 18 | ERROR | Id selector is used + 19 | ERROR | Id selector is used + 20 | ERROR | Id selector is used 21 | ERROR | Id selector is used 22 | ERROR | Id selector is used - 23 | ERROR | Id selector is used + 26 | ERROR | Id selector is used + 27 | ERROR | Id selector is used + 28 | ERROR | Id selector is used --------------------------------------------------------------------------------------------------------------------------------- diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less index 45eb999c803c7..dd37677b5b53b 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Less/_files/avoid-ids.less @@ -1,3 +1,8 @@ +// /** +// * Copyright © Magento, Inc. All rights reserved. +// * See COPYING.txt for license details. +// */ + #foo[bar], #foo[bar=bash], #foo[bar~=bash], From 89b54dd642f3e32fa1ef537aba54a536857b9cd6 Mon Sep 17 00:00:00 2001 From: Alex Paliarush <paliarus@adobe.com> Date: Fri, 5 Oct 2018 13:24:02 -0500 Subject: [PATCH 101/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization - Refactored performance optimization for config elements initialization --- .../Products/Attributes/Collection.php | 3 - .../Magento/GraphQl/Controller/GraphQl.php | 22 +++-- .../Magento/Framework/GraphQl/Config.php | 18 +++- .../GraphQl/Query/FieldExtractor.php | 95 ------------------- .../Framework/GraphQl/Query/Fields.php | 64 +++++++++++++ 5 files changed, 92 insertions(+), 110 deletions(-) delete mode 100644 lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php create mode 100644 lib/internal/Magento/Framework/GraphQl/Query/Fields.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php index 5218b055deec6..ab0531ad09513 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Attributes/Collection.php @@ -64,9 +64,6 @@ public function getAttributes() : AttributeCollection ['eq' => '1'] ] ); - $arrayOfAttributesRequested = \Magento\Framework\GraphQl\Query\FieldExtractor::$fieldsUsedInQuery; - //$this->collection->addFieldToFilter('attribute_code', ['eq' => 'cost1']); - //do a filter only by fields requested } return $this->collection->load(); diff --git a/app/code/Magento/GraphQl/Controller/GraphQl.php b/app/code/Magento/GraphQl/Controller/GraphQl.php index f1c22465032fa..c4a0b55de9bfc 100644 --- a/app/code/Magento/GraphQl/Controller/GraphQl.php +++ b/app/code/Magento/GraphQl/Controller/GraphQl.php @@ -17,6 +17,7 @@ use Magento\Framework\GraphQl\Schema\SchemaGeneratorInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\Webapi\Response; +use Magento\Framework\GraphQl\Query\Fields as QueryFields; /** * Front controller for web API GraphQL area. @@ -60,6 +61,11 @@ class GraphQl implements FrontControllerInterface */ private $requestProcessor; + /** + * @var QueryFields + */ + private $queryFields; + /** * @param Response $response * @param SchemaGeneratorInterface $schemaGenerator @@ -68,6 +74,7 @@ class GraphQl implements FrontControllerInterface * @param \Magento\Framework\GraphQl\Exception\ExceptionFormatter $graphQlError * @param \Magento\Framework\GraphQl\Query\Resolver\ContextInterface $resolverContext * @param HttpRequestProcessor $requestProcessor + * @param QueryFields $queryFields */ public function __construct( Response $response, @@ -76,7 +83,8 @@ public function __construct( QueryProcessor $queryProcessor, ExceptionFormatter $graphQlError, ContextInterface $resolverContext, - HttpRequestProcessor $requestProcessor + HttpRequestProcessor $requestProcessor, + QueryFields $queryFields ) { $this->response = $response; $this->schemaGenerator = $schemaGenerator; @@ -85,6 +93,7 @@ public function __construct( $this->graphQlError = $graphQlError; $this->resolverContext = $resolverContext; $this->requestProcessor = $requestProcessor; + $this->queryFields = $queryFields; } /** @@ -101,17 +110,16 @@ public function dispatch(RequestInterface $request) : ResponseInterface $this->requestProcessor->processHeaders($request); $data = $this->jsonSerializer->unserialize($request->getContent()); - $source = isset($data['query']) ? $data['query'] : ''; + $query = isset($data['query']) ? $data['query'] : ''; - $documentNode = \GraphQL\Language\Parser::parse(new \GraphQL\Language\Source($source ?: '', 'GraphQL')); // We have to extract queried field names to avoid instantiation of non necessary fields in webonyx schema - // FieldExtractor class needs to be rewritten it was copied from \GraphQL\Language\Printer - \Magento\Framework\GraphQl\Query\FieldExtractor::doExtract($documentNode); - + // Temporal coupling is required for performance optimization + $this->queryFields->setQuery($query); $schema = $this->schemaGenerator->generate(); + $result = $this->queryProcessor->process( $schema, - $source, + $query, $this->resolverContext, isset($data['variables']) ? $data['variables'] : [] ); diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index 312da5cf0b8d5..52735acc6d70f 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -10,6 +10,7 @@ use Magento\Framework\Config\DataInterface; use Magento\Framework\GraphQl\Config\ConfigElementFactoryInterface; use Magento\Framework\GraphQl\Config\ConfigElementInterface; +use Magento\Framework\GraphQl\Query\Fields as QueryFields; /** * Provides access to typing information for a configured GraphQL schema. @@ -26,16 +27,24 @@ class Config implements ConfigInterface */ private $configElementFactory; + /** + * @var QueryFields + */ + private $queryFields; + /** * @param DataInterface $data * @param ConfigElementFactoryInterface $configElementFactory + * @param QueryFields $queryFields */ public function __construct( DataInterface $data, - ConfigElementFactoryInterface $configElementFactory + ConfigElementFactoryInterface $configElementFactory, + QueryFields $queryFields ) { $this->configData = $data; $this->configElementFactory = $configElementFactory; + $this->queryFields = $queryFields; } /** @@ -54,11 +63,10 @@ public function getConfigElement(string $configElementName) : ConfigElementInter ); } - //limiting the data from config array that is cached - if (isset($data['fields'])) { + $fieldsInQuery = $this->queryFields->getFieldsUsedInQuery(); + if (isset($data['fields']) && !empty($fieldsInQuery)) { foreach ($data['fields'] as $fieldName => $fieldConfig) { - $arrayOfAttributesRequested = \Magento\Framework\GraphQl\Query\FieldExtractor::$fieldsUsedInQuery; - if (!isset($arrayOfAttributesRequested[$fieldName])) { + if (!isset($fieldsInQuery[$fieldName])) { unset($data['fields'][$fieldName]); } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php b/lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php deleted file mode 100644 index 429d03e93d1bb..0000000000000 --- a/lib/internal/Magento/Framework/GraphQl/Query/FieldExtractor.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\GraphQl\Query; - -use GraphQL\Language\AST\ArgumentNode; -use GraphQL\Language\AST\DirectiveDefinitionNode; -use GraphQL\Language\AST\EnumTypeDefinitionNode; -use GraphQL\Language\AST\EnumTypeExtensionNode; -use GraphQL\Language\AST\EnumValueDefinitionNode; -use GraphQL\Language\AST\FieldDefinitionNode; -use GraphQL\Language\AST\InputObjectTypeDefinitionNode; -use GraphQL\Language\AST\InputObjectTypeExtensionNode; -use GraphQL\Language\AST\InputValueDefinitionNode; -use GraphQL\Language\AST\InterfaceTypeDefinitionNode; -use GraphQL\Language\AST\InterfaceTypeExtensionNode; -use GraphQL\Language\AST\ListValueNode; -use GraphQL\Language\AST\BooleanValueNode; -use GraphQL\Language\AST\DirectiveNode; -use GraphQL\Language\AST\DocumentNode; -use GraphQL\Language\AST\EnumValueNode; -use GraphQL\Language\AST\FieldNode; -use GraphQL\Language\AST\FloatValueNode; -use GraphQL\Language\AST\FragmentDefinitionNode; -use GraphQL\Language\AST\FragmentSpreadNode; -use GraphQL\Language\AST\InlineFragmentNode; -use GraphQL\Language\AST\IntValueNode; -use GraphQL\Language\AST\ListTypeNode; -use GraphQL\Language\AST\NamedTypeNode; -use GraphQL\Language\AST\Node; -use GraphQL\Language\AST\NodeKind; -use GraphQL\Language\AST\NonNullTypeNode; -use GraphQL\Language\AST\NullValueNode; -use GraphQL\Language\AST\ObjectFieldNode; -use GraphQL\Language\AST\ObjectTypeDefinitionNode; -use GraphQL\Language\AST\ObjectValueNode; -use GraphQL\Language\AST\OperationDefinitionNode; -use GraphQL\Language\AST\OperationTypeDefinitionNode; -use GraphQL\Language\AST\ScalarTypeDefinitionNode; -use GraphQL\Language\AST\ScalarTypeExtensionNode; -use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SelectionSetNode; -use GraphQL\Language\AST\StringValueNode; -use GraphQL\Language\AST\ObjectTypeExtensionNode; -use GraphQL\Language\AST\UnionTypeDefinitionNode; -use GraphQL\Language\AST\UnionTypeExtensionNode; -use GraphQL\Language\AST\VariableDefinitionNode; -use GraphQL\Utils\Utils; - -/** - * Prints AST to string. Capable of printing GraphQL queries and Type definition language. - * Useful for pretty-printing queries or printing back AST for logging, documentation, etc. - * - * Usage example: - * - * ```php - * $query = 'query myQuery {someField}'; - * $ast = GraphQL\Language\Parser::parse($query); - * $printed = GraphQL\Language\Printer::doPrint($ast); - * ``` - * This class was copied from \GraphQL\Language\Printer - */ -class FieldExtractor -{ - - public static $fieldsUsedInQuery = []; - /** - * Prints AST to string. Capable of printing GraphQL queries and Type definition language. - * - * @api - * @param Node $ast - * @return string - */ - public static function doExtract($ast) - { - static $instance; - $instance = $instance ?: new static(); - return $instance->extract($ast); - } - - public function extract($ast) - { - return \GraphQL\Language\Visitor::visit($ast, [ - 'leave' => [ - NodeKind::NAME => function(Node $node) { - self::$fieldsUsedInQuery[$node->value] = $node->value; - } - ] - ]); - } -} diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Fields.php b/lib/internal/Magento/Framework/GraphQl/Query/Fields.php new file mode 100644 index 0000000000000..fb18fa1bfab8a --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Query/Fields.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\GraphQl\Query; + +use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\NodeKind; + +/** + * This class holds a list of all queried fields and is used to enable performance optimization for schema loading. + */ +class Fields +{ + /** + * @var string[] + */ + private $fieldsUsedInQuery = []; + + /** + * Prints AST to string. Capable of printing GraphQL queries and Type definition language. + * + * @param string $query + * @return void + */ + public function setQuery($query) + { + $queryFields = []; + try { + $queryAst = \GraphQL\Language\Parser::parse(new \GraphQL\Language\Source($query ?: '', 'GraphQL')); + \GraphQL\Language\Visitor::visit( + $queryAst, + [ + 'leave' => [ + NodeKind::NAME => function (Node $node) use (&$queryFields) { + $queryFields[$node->value] = $node->value; + } + ] + ] + ); + } catch (\Exception $e) { + } + if (isset($queryFields['IntrospectionQuery'])) { + // It must be possible to query any fields during introspection query + $queryFields = []; + } + $this->fieldsUsedInQuery = $queryFields; + } + + /** + * Get list of fields used in GraphQL query. + * + * This method is stateful and relies on the query being set with setQuery. + * + * @return string[] + */ + public function getFieldsUsedInQuery() + { + return $this->fieldsUsedInQuery; + } +} From ee4e6fdd384f7249028aa5f19b6fff9c419dda64 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Fri, 5 Oct 2018 13:48:23 -0500 Subject: [PATCH 102/118] MAGETWO-95346: Configurable and Bundled Product InvoiceOrder Api Service - Fixed static test and soap tests --- app/code/Magento/Sales/Model/Service/InvoiceService.php | 5 +++-- .../Magento/Sales/Service/V1/OrderInvoiceCreateTest.php | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php index fa2dcff191775..2806f76b1389b 100644 --- a/app/code/Magento/Sales/Model/Service/InvoiceService.php +++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php @@ -125,6 +125,8 @@ public function setVoid($id) } /** + * Creates an invoice based on the order and quantities provided + * * @param Order $order * @param array $qtys * @return \Magento\Sales\Model\Order\Invoice @@ -192,8 +194,7 @@ private function prepareItemsQty(Order $order, array $qtys = []) } /** - * Check if order item can be invoiced. Dummy item can be invoiced or with his children or - * with parent item which is included to invoice + * Check if order item can be invoiced. * * @param \Magento\Sales\Api\Data\OrderItemInterface $item * @param array $qtys diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php index 941421d456ca9..f6194db6d8ebb 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php @@ -96,7 +96,7 @@ public function testInvoiceCreate() * * @expectedException \Exception * @codingStandardsIgnoreStart - * @expectedExceptionMessage {"message":"Invoice Document Validation Error(s):\nThe invoice can't be created without products. Add products and try again."} + * @expectedExceptionMessageRegExp /Invoice Document Validation Error\(s\):(?:\n|\\n)The invoice can't be created without products. Add products and try again./ * @codingStandardsIgnoreEnd * @magentoApiDataFixture Magento/Sales/_files/order_with_bundle.php */ @@ -119,6 +119,7 @@ public function testOrderWithBundleInvoicedWithInvalidQuantitiesReturnsError() ]; $requestData = [ + 'orderId' => $existingOrder->getId(), 'notify' => true, 'appendComment' => true, 'items' => [ @@ -129,6 +130,7 @@ public function testOrderWithBundleInvoicedWithInvalidQuantitiesReturnsError() ], 'comment' => [ 'comment' => 'Test offline', + 'isVisibleOnFront' => 1, ], ]; @@ -140,7 +142,7 @@ public function testOrderWithBundleInvoicedWithInvalidQuantitiesReturnsError() * * @expectedException \Exception * @codingStandardsIgnoreStart - * @expectedExceptionMessage {"message":"Invoice Document Validation Error(s):\nThe invoice can't be created without products. Add products and try again."} + * @expectedExceptionMessageRegExp /Invoice Document Validation Error\(s\):(?:\n|\\n)The invoice can't be created without products. Add products and try again./ * @codingStandardsIgnoreEnd * @magentoApiDataFixture Magento/Sales/_files/order_configurable_product.php */ @@ -163,6 +165,7 @@ public function testOrderWithConfigurableProductInvoicedWithInvalidQuantitiesRet ]; $requestData = [ + 'orderId' => $existingOrder->getId(), 'notify' => true, 'appendComment' => true, 'items' => [ @@ -173,6 +176,7 @@ public function testOrderWithConfigurableProductInvoicedWithInvalidQuantitiesRet ], 'comment' => [ 'comment' => 'Test offline', + 'isVisibleOnFront' => 1, ], ]; From 0ae24277ba359cc0e338ffdb626c36e485175586 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Fri, 5 Oct 2018 14:48:56 -0500 Subject: [PATCH 103/118] MAGETWO-91057: MFTF Test failure - Add products to wishlist from different stores - unskip test --- .../Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml index c9a0c0cc0f8bc..f8a1707e6c23a 100644 --- a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml +++ b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml @@ -15,9 +15,6 @@ <description value="All products added to wishlist should be visible on any store. Even if product visibility was set to 'Not Visible Individually' for this store"/> <group value="wishlist"/> <severity value="AVERAGE"/> - <skip> - <issueId value="MAGETWO-93980"/> - </skip> </annotations> <before> <createData entity="customStoreGroup" stepKey="storeGroup"/> From 9134496c5d649932a5315f92191e88c8cbcc2015 Mon Sep 17 00:00:00 2001 From: Cari Spruiell <spruiell@adobe.com> Date: Fri, 5 Oct 2018 14:54:25 -0500 Subject: [PATCH 104/118] MC-3857: Products Content Type is broken on Dynamic Block page - fix static test failures --- app/code/Magento/CatalogWidget/Block/Product/ProductsList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index 8bec76428316b..ed17634aa48c1 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -227,7 +227,7 @@ public function getProductPriceHtml( /** * Before rendering html, but after trying to load cache * - * {@inheritdoc} + * @return $this */ protected function _beforeToHtml() { From 436d8a65b2988b851e6331b63ca6fe5f71d05885 Mon Sep 17 00:00:00 2001 From: Alex Paliarush <paliarus@adobe.com> Date: Fri, 5 Oct 2018 16:05:58 -0500 Subject: [PATCH 105/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization - Optimized category data loading for products query --- .../Model/Category/Hydrator.php | 14 +++++--- .../Model/Resolver/Categories.php | 33 ++++++++----------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php b/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php index da4ec37c51da4..f0cdab9498abb 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php @@ -8,6 +8,7 @@ namespace Magento\CatalogGraphQl\Model\Category; use Magento\Catalog\Api\Data\CategoryInterface; +use Magento\Catalog\Model\Category; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\CustomAttributesFlattener; use Magento\Framework\Reflection\DataObjectProcessor; @@ -41,14 +42,19 @@ public function __construct( /** * Hydrate and flatten category object to flat array * - * @param CategoryInterface $category + * @param Category $category + * @param bool $basicFieldsOnly Set to false to avoid expensive hydration, used for performance optimization * @return array */ - public function hydrateCategory(CategoryInterface $category) : array + public function hydrateCategory(Category $category, $basicFieldsOnly = false) : array { - $categoryData = $this->dataObjectProcessor->buildOutputDataArray($category, CategoryInterface::class); + if ($basicFieldsOnly) { + $categoryData = $category->getData(); + } else { + $categoryData = $this->dataObjectProcessor->buildOutputDataArray($category, CategoryInterface::class); + $categoryData['product_count'] = $category->getProductCount(); + } $categoryData['id'] = $category->getId(); - $categoryData['product_count'] = $category->getProductCount(); $categoryData['children'] = []; $categoryData['available_sort_by'] = $category->getAvailableSortBy(); return $this->flattener->flatten($categoryData); diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php index 11614e79bba22..7fe679b18d866 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php @@ -17,7 +17,7 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; -use Magento\Framework\Reflection\DataObjectProcessor; +use Magento\CatalogGraphQl\Model\Category\Hydrator as CategoryHydrator; /** * Resolver for category objects the product is assigned to. @@ -36,11 +36,6 @@ class Categories implements ResolverInterface */ private $categoryIds = []; - /** - * @var DataObjectProcessor - */ - private $dataObjectProcessor; - /** * @var AttributesJoiner */ @@ -57,25 +52,29 @@ class Categories implements ResolverInterface private $valueFactory; /** - * Category constructor. + * @var CategoryHydrator + */ + private $categoryHydrator; + + /** * @param CollectionFactory $collectionFactory - * @param DataObjectProcessor $dataObjectProcessor * @param AttributesJoiner $attributesJoiner * @param CustomAttributesFlattener $customAttributesFlattener * @param ValueFactory $valueFactory + * @param CategoryHydrator $categoryHydrator */ public function __construct( CollectionFactory $collectionFactory, - DataObjectProcessor $dataObjectProcessor, AttributesJoiner $attributesJoiner, CustomAttributesFlattener $customAttributesFlattener, - ValueFactory $valueFactory + ValueFactory $valueFactory, + CategoryHydrator $categoryHydrator ) { $this->collection = $collectionFactory->create(); - $this->dataObjectProcessor = $dataObjectProcessor; $this->attributesJoiner = $attributesJoiner; $this->customAttributesFlattener = $customAttributesFlattener; $this->valueFactory = $valueFactory; + $this->categoryHydrator = $categoryHydrator; } /** @@ -109,8 +108,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value if (in_array($item->getId(), $categoryIds)) { // Try to extract all requested fields from the loaded collection data - $categories[$item->getId()] = $item->getData(); - $categories[$item->getId()]['id'] = $item->getId(); + $categories[$item->getId()] = $this->categoryHydrator->hydrateCategory($item, true); $requestedFields = $that->attributesJoiner->getQueryFields($info->fieldNodes[0]); $extractedFields = array_keys($categories[$item->getId()]); $foundFields = array_intersect($requestedFields, $extractedFields); @@ -119,13 +117,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value } // If not all requested fields were extracted from the collection, start more complex extraction - $categories[$item->getId()] = $this->dataObjectProcessor->buildOutputDataArray( - $item, - CategoryInterface::class - ); - $categories[$item->getId()] = $this->customAttributesFlattener - ->flatten($categories[$item->getId()]); - $categories[$item->getId()]['product_count'] = $item->getProductCount(); + $categories[$item->getId()] = $this->categoryHydrator->hydrateCategory($item); + } } From 87bb433ce2ccc3de2a3f89de9e40f70515d43fa5 Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@adobe.com> Date: Fri, 5 Oct 2018 17:28:11 -0500 Subject: [PATCH 106/118] MAGETWO-95130: CMS block cannot be deleted - added functional test to cover the bug fix --- .../SearchBlockOnGridPageActionGroup.xml | 23 +++++++++++++++++++ .../CmsNewBlockBlockActionsSection.xml | 4 ++++ .../Mftf/Test/AdminCreateCmsBlockTest.xml | 3 +++ 3 files changed, 30 insertions(+) diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/SearchBlockOnGridPageActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/SearchBlockOnGridPageActionGroup.xml index e31eb44146af4..12205aeed8fa3 100644 --- a/app/code/Magento/Cms/Test/Mftf/ActionGroup/SearchBlockOnGridPageActionGroup.xml +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/SearchBlockOnGridPageActionGroup.xml @@ -16,4 +16,27 @@ <waitForLoadingMaskToDisappear stepKey="waitForSecondIdSortDescendingToFinish2" /> <waitForElementVisible selector="{{WidgetSection.BlockPage(Block.identifier)}}" stepKey="waitForBlockTitle" /> </actionGroup> + <actionGroup name ="deleteBlock"> + <arguments> + <argument name="Block" defaultValue=""/> + </arguments> + <amOnPage url="{{CmsBlocksPage.url}}" stepKey="navigateToCMSBlocksGrid"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <conditionalClick selector="{{BlockPageActionsSection.clearAll}}" dependentSelector="{{BlockPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <click selector="{{BlockPageActionsSection.FilterBtn}}" stepKey="clickFilterBtn"/> + <fillField selector="{{BlockPageActionsSection.URLKey}}" userInput="{{Block.identifier}}" stepKey="fillBlockIdentifierInput"/> + <click selector="{{BlockPageActionsSection.ApplyFiltersBtn}}" stepKey="applyFilter"/> + <waitForLoadingMaskToDisappear stepKey="waitForGridToLoadResults" /> + <waitForElementVisible selector="{{BlockPageActionsSection.select(Block.identifier)}}" stepKey="waitForCMSPageGrid" /> + <click selector="{{BlockPageActionsSection.select(Block.identifier)}}" stepKey="clickSelect" /> + <waitForElementVisible selector="{{BlockPageActionsSection.edit(Block.identifier)}}" stepKey="waitForEditLink" /> + <click selector="{{BlockPageActionsSection.edit(Block.identifier)}}" stepKey="clickEdit" /> + <waitForLoadingMaskToDisappear stepKey="waitForPageToLoad" /> + <click selector="{{CmsBlockBlockActionSection.deleteBlock}}" stepKey="deleteBlock"/> + <waitForElementVisible selector="{{CmsBlockBlockActionSection.deleteConfirm}}" stepKey="waitForOkButtonToBeVisible"/> + <click selector="{{CmsBlockBlockActionSection.deleteConfirm}}" stepKey="clickOkButton"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <see userInput="You deleted the block." stepKey="seeSuccessMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Cms/Test/Mftf/Section/CmsNewBlockBlockActionsSection.xml b/app/code/Magento/Cms/Test/Mftf/Section/CmsNewBlockBlockActionsSection.xml index 2e783af6bfc6a..4c6014af51264 100644 --- a/app/code/Magento/Cms/Test/Mftf/Section/CmsNewBlockBlockActionsSection.xml +++ b/app/code/Magento/Cms/Test/Mftf/Section/CmsNewBlockBlockActionsSection.xml @@ -24,4 +24,8 @@ <section name="BlockContentSection"> <element name="TextArea" type="input" selector="#cms_block_form_content"/> </section> + <section name="CmsBlockBlockActionSection"> + <element name="deleteBlock" type="button" selector="#delete" timeout="30"/> + <element name="deleteConfirm" type="button" selector=".action-primary.action-accept" timeout="60"/> + </section> </sections> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml index e2c74823dfffb..7ab0d9209dde3 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml @@ -23,6 +23,9 @@ <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> </before> <after> + <actionGroup ref="deleteBlock" stepKey="deleteCreatedBlock"> + <argument name="Block" value="_defaultBlock"/> + </actionGroup> <actionGroup ref="logout" stepKey="logout"/> </after> <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnBlocksCreationForm"/> From e32303ab2a4eeb4001a1b8627f60ae8ba993d919 Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Mon, 8 Oct 2018 08:15:23 -0500 Subject: [PATCH 107/118] MAGETWO-83089: Functional test failure in UpdateAdminUserRoleEntityTest --- .../Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.xml index 1f1530b08b28a..224ccbce10f96 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.xml @@ -17,7 +17,6 @@ <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" /> </variation> <variation name="UpdateAdminUserRoleEntityTestVariation2"> - <data name="issue" xsi:type="string">MAGETWO-65658: [FT] User with restricted access can't log in to Admin in UpdateAdminUserEntityTest</data> <data name="user/dataset" xsi:type="string">default</data> <data name="role/data/resource_access" xsi:type="string">Custom</data> <data name="role/data/roles_resources" xsi:type="string">Sales</data> From 0b5258860d19ce8541d2043085b33ac8aee2c336 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 8 Oct 2018 09:46:05 -0500 Subject: [PATCH 108/118] MAGETWO-95534: Random integration test failure - Fixed Magento.Cms.Model.PageTest.testUpdateTime --- .../testsuite/Magento/Cms/Model/PageTest.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php index 42697e1b66b7f..83e7c678ffc51 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php @@ -6,6 +6,7 @@ namespace Magento\Cms\Model; use Magento\Cms\Api\PageRepositoryInterface; +use Magento\Framework\App\ResourceConnection; use Magento\Framework\Stdlib\DateTime\DateTime; /** @@ -79,13 +80,27 @@ public function testGenerateIdentifierFromTitle($data, $expectedIdentifier) public function testUpdateTime() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** + * @var $db \Magento\Framework\DB\Adapter\AdapterInterface + */ + $db = $objectManager->get(\Magento\Framework\App\ResourceConnection::class) + ->getConnection(ResourceConnection::DEFAULT_CONNECTION); + /** @var \Magento\Cms\Model\Page $page */ $page = $objectManager->create(\Magento\Cms\Model\Page::class); $page->setData(['title' => 'Test', 'stores' => [1]]); + $beforeTimestamp = $db->fetchCol('SELECT UNIX_TIMESTAMP()')[0]; $page->save(); + $afterTimestamp = $db->fetchCol('SELECT UNIX_TIMESTAMP()')[0]; $page = $objectManager->get(PageRepositoryInterface::class)->getById($page->getId()); - $date = $objectManager->get(DateTime::class)->date(); - $this->assertEquals($date, $page->getUpdateTime()); + $pageTimestamp = strtotime($page->getUpdateTime()); + + /* + * These checks prevent a race condition MAGETWO-95534 + */ + $this->assertGreaterThanOrEqual($beforeTimestamp, $pageTimestamp); + $this->assertLessThanOrEqual($afterTimestamp, $pageTimestamp); } public function generateIdentifierFromTitleDataProvider() : array From 14d4016e68a6ceb9dbcb383253301917501885db Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 8 Oct 2018 11:25:29 -0500 Subject: [PATCH 109/118] MAGETWO-95429: ShipOrder API with No Tracking Number Error Message - Changed class to use existing collection - Added api test --- .../Magento/Sales/Model/Order/Shipment.php | 9 ++---- .../Sales/Service/V1/ShipOrderTest.php | 31 ++++++++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php index 8be12ec6ad57f..1da9ff88c9a16 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment.php +++ b/app/code/Magento/Sales/Model/Order/Shipment.php @@ -574,13 +574,10 @@ public function setItems($items) public function getTracks() { if ($this->getData(ShipmentInterface::TRACKS) === null) { - $collection = $this->_trackCollectionFactory->create()->setShipmentFilter($this->getId()); - if ($this->getId()) { - foreach ($collection as $item) { - $item->setShipment($this); - } - $this->setData(ShipmentInterface::TRACKS, $collection->getItems()); + foreach ($this->getTracksCollection() as $item) { + $item->setShipment($this); } + $this->setData(ShipmentInterface::TRACKS, $this->getTracksCollection()->getItems()); } return $this->getData(ShipmentInterface::TRACKS); } diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php index 1d854331731ab..580de22855917 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php @@ -25,7 +25,6 @@ class ShipOrderTest extends \Magento\TestFramework\TestCase\WebapiAbstract protected function setUp() { - $this->markTestIncomplete('https://github.com/magento-engcom/msi/issues/1335'); $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $this->shipmentRepository = $this->objectManager->get( @@ -38,6 +37,7 @@ protected function setUp() */ public function testConfigurableShipOrder() { + $this->markTestIncomplete('https://github.com/magento-engcom/msi/issues/1335'); $productsQuantity = 1; /** @var \Magento\Sales\Model\Order $existingOrder */ @@ -132,6 +132,35 @@ public function testShipOrder() ); } + /** + * Tests that not providing a tracking number produces the correct error. See MAGETWO-95429 + * @expectedException \Exception + * @expectedExceptionMessageRegExp /Shipment Document Validation Error\(s\):(?:\n|\\n)Please enter a tracking number./ + * @magentoApiDataFixture Magento/Sales/_files/order_new.php + */ + public function testShipOrderWithoutTrackingNumberReturnsError() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + $requestData = [ + 'orderId' => $existingOrder->getId(), + 'comment' => [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1, + ], + 'tracks' => [ + [ + 'title' => 'Simple shipment track', + 'carrier_code' => 'UPS' + ] + ] + ]; + + $this->_webApiCall($this->getServiceInfo($existingOrder), $requestData); + } + /** * @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_separately.php */ From a52725d41187e32c30864a5c754efbdff8c2fd72 Mon Sep 17 00:00:00 2001 From: Alex Paliarush <paliarus@adobe.com> Date: Mon, 8 Oct 2018 11:27:41 -0500 Subject: [PATCH 110/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization - Fixed code style violations --- .../Catalog/Model/Product/Media/Config.php | 41 +++++++++++-------- .../Model/Resolver/Categories.php | 5 +-- .../Magento/Framework/GraphQl/Config.php | 11 ++--- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Media/Config.php b/app/code/Magento/Catalog/Model/Product/Media/Config.php index b01f254b8377b..33af93db13b4c 100644 --- a/app/code/Magento/Catalog/Model/Product/Media/Config.php +++ b/app/code/Magento/Catalog/Model/Product/Media/Config.php @@ -10,11 +10,9 @@ use Magento\Store\Model\StoreManagerInterface; /** - * Catalog product media config + * Catalog product media config. * * @api - * - * @author Magento Core Team <core@magentocommerce.com> * @since 100.0.2 */ class Config implements ConfigInterface @@ -45,8 +43,7 @@ public function __construct(StoreManagerInterface $storeManager) } /** - * Filesystem directory path of product images - * relatively to media folder + * Get filesystem directory path for product images relative to the media directory. * * @return string */ @@ -56,8 +53,7 @@ public function getBaseMediaPathAddition() } /** - * Web-based directory path of product images - * relatively to media folder + * Get web-based directory path for product images relative to the media directory. * * @return string */ @@ -67,7 +63,7 @@ public function getBaseMediaUrlAddition() } /** - * @return string + * @inheritdoc */ public function getBaseMediaPath() { @@ -75,7 +71,7 @@ public function getBaseMediaPath() } /** - * @return string + * @inheritdoc */ public function getBaseMediaUrl() { @@ -84,8 +80,7 @@ public function getBaseMediaUrl() } /** - * Filesystem directory path of temporary product images - * relatively to media folder + * Filesystem directory path of temporary product images relative to the media directory. * * @return string */ @@ -95,6 +90,8 @@ public function getBaseTmpMediaPath() } /** + * Get temporary base media URL. + * * @return string */ public function getBaseTmpMediaUrl() @@ -105,8 +102,7 @@ public function getBaseTmpMediaUrl() } /** - * @param string $file - * @return string + * @inheritdoc */ public function getMediaUrl($file) { @@ -114,8 +110,7 @@ public function getMediaUrl($file) } /** - * @param string $file - * @return string + * @inheritdoc */ public function getMediaPath($file) { @@ -123,6 +118,8 @@ public function getMediaPath($file) } /** + * Get temporary media URL. + * * @param string $file * @return string */ @@ -132,8 +129,7 @@ public function getTmpMediaUrl($file) } /** - * Part of URL of temporary product images - * relatively to media folder + * Part of URL of temporary product images relative to the media directory. * * @param string $file * @return string @@ -144,7 +140,7 @@ public function getTmpMediaShortUrl($file) } /** - * Part of URL of product images relatively to media folder + * Part of URL of product images relatively to media folder. * * @param string $file * @return string @@ -155,6 +151,8 @@ public function getMediaShortUrl($file) } /** + * Get path to the temporary media. + * * @param string $file * @return string */ @@ -164,6 +162,8 @@ public function getTmpMediaPath($file) } /** + * Process file path. + * * @param string $file * @return string */ @@ -173,18 +173,23 @@ protected function _prepareFile($file) } /** + * Get codes of media attribute. + * * @return array * @since 100.0.4 */ public function getMediaAttributeCodes() { if (!isset($this->mediaAttributeCodes)) { + // the in-memory object-level caching allows to prevent unnecessary calls to the DB $this->mediaAttributeCodes = $this->getAttributeHelper()->getAttributeCodesByFrontendType('media_image'); } return $this->mediaAttributeCodes; } /** + * Get attribute helper. + * * @return Attribute */ private function getAttributeHelper() diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php index 7fe679b18d866..fdc9e5f083b72 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php @@ -78,7 +78,8 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc + * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) @@ -106,7 +107,6 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value /** @var CategoryInterface | \Magento\Catalog\Model\Category $item */ foreach ($this->collection as $item) { if (in_array($item->getId(), $categoryIds)) { - // Try to extract all requested fields from the loaded collection data $categories[$item->getId()] = $this->categoryHydrator->hydrateCategory($item, true); $requestedFields = $that->attributesJoiner->getQueryFields($info->fieldNodes[0]); @@ -118,7 +118,6 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value // If not all requested fields were extracted from the collection, start more complex extraction $categories[$item->getId()] = $this->categoryHydrator->hydrateCategory($item); - } } diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index 52735acc6d70f..ff4c920d2cd6a 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -53,6 +53,7 @@ public function __construct( * @param string $configElementName * @return ConfigElementInterface * @throws \LogicException + * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ public function getConfigElement(string $configElementName) : ConfigElementInterface { @@ -65,11 +66,11 @@ public function getConfigElement(string $configElementName) : ConfigElementInter $fieldsInQuery = $this->queryFields->getFieldsUsedInQuery(); if (isset($data['fields']) && !empty($fieldsInQuery)) { - foreach ($data['fields'] as $fieldName => $fieldConfig) { - if (!isset($fieldsInQuery[$fieldName])) { - unset($data['fields'][$fieldName]); - } - } + foreach ($data['fields'] as $fieldName => $fieldConfig) { + if (!isset($fieldsInQuery[$fieldName])) { + unset($data['fields'][$fieldName]); + } + } } return $this->configElementFactory->createFromConfigData($data); From e4094c93a041251075b25f4889a171c64ef37d0c Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 8 Oct 2018 12:42:27 -0500 Subject: [PATCH 111/118] MAGETWO-95429: ShipOrder API with No Tracking Number Error Message - Build stabilization --- app/code/Magento/Sales/Model/Order/Shipment.php | 17 +++++++++++++++-- .../Magento/Sales/Service/V1/ShipOrderTest.php | 4 ++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php index 1da9ff88c9a16..ebedc869e14bd 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment.php +++ b/app/code/Magento/Sales/Model/Order/Shipment.php @@ -277,6 +277,8 @@ public function register() } /** + * Retrieves the collection used to track the shipment's items + * * @return mixed */ public function getItemsCollection() @@ -295,6 +297,8 @@ public function getItemsCollection() } /** + * Retrieves all non-deleted items from the shipment + * * @return array */ public function getAllItems() @@ -309,6 +313,8 @@ public function getAllItems() } /** + * Retrieves an item from the shipment using its ID + * * @param string|int $itemId * @return bool|\Magento\Sales\Model\Order\Shipment\Item */ @@ -323,6 +329,8 @@ public function getItemById($itemId) } /** + * Adds an item to the shipment + * * @param \Magento\Sales\Model\Order\Shipment\Item $item * @return $this */ @@ -353,6 +361,8 @@ public function getTracksCollection() } /** + * Retrieves all available tracks in the collection that aren't deleted + * * @return array */ public function getAllTracks() @@ -367,6 +377,8 @@ public function getAllTracks() } /** + * Retrieves a track using its ID + * * @param string|int $trackId * @return bool|\Magento\Sales\Model\Order\Shipment\Track */ @@ -381,6 +393,8 @@ public function getTrackById($trackId) } /** + * Addes a track to the collection and associates the shipment to the track + * * @param \Magento\Sales\Model\Order\Shipment\Track $track * @return $this */ @@ -409,8 +423,7 @@ public function addTrack(\Magento\Sales\Model\Order\Shipment\Track $track) } /** - * Adds comment to shipment with additional possibility to send it to customer via email - * and show it in customer account + * Adds comment to shipment with option to send it to customer via email and show it in customer account * * @param \Magento\Sales\Model\Order\Shipment\Comment|string $comment * @param bool $notify diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php index 580de22855917..e2a156cc6fbfc 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php @@ -135,11 +135,15 @@ public function testShipOrder() /** * Tests that not providing a tracking number produces the correct error. See MAGETWO-95429 * @expectedException \Exception + * @codingStandardsIgnoreStart * @expectedExceptionMessageRegExp /Shipment Document Validation Error\(s\):(?:\n|\\n)Please enter a tracking number./ + * @codingStandardsIgnoreEnd * @magentoApiDataFixture Magento/Sales/_files/order_new.php */ public function testShipOrderWithoutTrackingNumberReturnsError() { + $this->_markTestAsRestOnly('SOAP requires an tracking number to be provided so this case is not possible.'); + /** @var \Magento\Sales\Model\Order $existingOrder */ $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) ->loadByIncrementId('100000001'); From 1fa4f0d29dcf67634a65ca62cc7b68b394e2231c Mon Sep 17 00:00:00 2001 From: Iryna Lagno <ilagno@adobe.com> Date: Mon, 8 Oct 2018 13:54:34 -0500 Subject: [PATCH 112/118] MAGETWO-87454: Catalog Products List widget doesn't work with 'contains/not contains' operator --- .../CatalogWidget/Block/Product/ProductListTest.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php b/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php index 2f2029d2f13e1..2695948e78314 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php @@ -136,12 +136,14 @@ private function performAssertions(int $count) * Check that collection returns correct result if use not contains operator for string attribute * * @magentoDbIsolation disabled - * @magentoDataFixture Magento/Catalog/_files/product_special_price.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_xss.php * @magentoDataFixture Magento/Catalog/_files/product_virtual.php * @dataProvider createCollectionForSkuDataProvider + * @param string $encodedConditions + * @param string $sku * @return void */ - public function testCreateCollectionForSku($encodedConditions) + public function testCreateCollectionForSku($encodedConditions, $sku) { $this->block->setData('conditions_encoded', $encodedConditions); $productCollection = $this->block->createCollection(); @@ -151,7 +153,7 @@ public function testCreateCollectionForSku($encodedConditions) $productCollection->count(), "Product collection was not filtered according to the widget condition." ); - $this->assertEquals('virtual-product', $productCollection->getFirstItem()->getSku()); + $this->assertEquals($sku, $productCollection->getFirstItem()->getSku()); } /** @@ -163,11 +165,11 @@ public function createCollectionForSkuDataProvider() 'contains' => ['^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,' . '`aggregator`:`all`,`value`:`1`,`new_child`:``^],' . '`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,' - . '`attribute`:`sku`,`operator`:`^[^]`,`value`:`virtual`^]^]'], + . '`attribute`:`sku`,`operator`:`^[^]`,`value`:`virtual`^]^]' , 'virtual-product'], 'not contains' => ['^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,' . '`aggregator`:`all`,`value`:`1`,`new_child`:``^],' . '`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,' - . '`attribute`:`sku`,`operator`:`!^[^]`,`value`:`simple`^]^]'] + . '`attribute`:`sku`,`operator`:`!^[^]`,`value`:`virtual`^]^]', 'product-with-xss'] ]; } } From 3aa29557064f31cb4bf8c72d3e8c3e3bff78ba99 Mon Sep 17 00:00:00 2001 From: Volodymyr Kublytskyi <vkublytskyi@magento.com> Date: Mon, 8 Oct 2018 23:49:29 +0300 Subject: [PATCH 113/118] Declare index for schema consistency --- .../AsynchronousOperations/etc/db_schema.xml | 3 + .../etc/db_schema_whitelist.json | 88 ++++++++++--------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml index 94ee5a16b5b84..342326e6666f1 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml @@ -27,6 +27,9 @@ <constraint xsi:type="unique" name="MAGENTO_BULK_UUID"> <column name="uuid"/> </constraint> + <index name="MAGENTO_BULK_USER_ID_ADMIN_USER_USER_ID" indexType="btree"> + <column name="user_id"/> + </index> </table> <table name="magento_operation" resource="default" engine="innodb" comment="Operation entity"> <column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true" diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json index 365c8d5b9b0b1..423b7553ced2a 100644 --- a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json @@ -1,47 +1,51 @@ { - "magento_bulk": { - "column": { - "id": true, - "uuid": true, - "user_id": true, - "user_type": true, - "description": true, - "operation_count": true, - "start_time": true + "magento_bulk": { + "column": { + "id": true, + "uuid": true, + "user_id": true, + "user_type": true, + "description": true, + "operation_count": true, + "start_time": true + }, + "index": { + "MAGENTO_BULK_USER_ID_ADMIN_USER_USER_ID": true, + "MAGENTO_BULK_USER_ID": true + }, + "constraint": { + "PRIMARY": true, + "MAGENTO_BULK_UUID": true + } }, - "constraint": { - "PRIMARY": true, - "MAGENTO_BULK_UUID": true - } - }, - "magento_operation": { - "column": { - "id": true, - "bulk_uuid": true, - "topic_name": true, - "serialized_data": true, - "result_serialized_data": true, - "status": true, - "error_code": true, - "result_message": true - }, - "index": { - "MAGENTO_OPERATION_BULK_UUID_ERROR_CODE": true - }, - "constraint": { - "PRIMARY": true, - "MAGENTO_OPERATION_BULK_UUID_MAGENTO_BULK_UUID": true - } - }, - "magento_acknowledged_bulk": { - "column": { - "id": true, - "bulk_uuid": true + "magento_operation": { + "column": { + "id": true, + "bulk_uuid": true, + "topic_name": true, + "serialized_data": true, + "result_serialized_data": true, + "status": true, + "error_code": true, + "result_message": true + }, + "index": { + "MAGENTO_OPERATION_BULK_UUID_ERROR_CODE": true + }, + "constraint": { + "PRIMARY": true, + "MAGENTO_OPERATION_BULK_UUID_MAGENTO_BULK_UUID": true + } }, - "constraint": { - "PRIMARY": true, - "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID_MAGENTO_BULK_UUID": true, - "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID": true + "magento_acknowledged_bulk": { + "column": { + "id": true, + "bulk_uuid": true + }, + "constraint": { + "PRIMARY": true, + "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID_MAGENTO_BULK_UUID": true, + "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID": true + } } - } } \ No newline at end of file From f7088960e269d2614258a39d9d97dc8ffe1c067d Mon Sep 17 00:00:00 2001 From: Volodymyr Kublytskyi <vkublytskyi@magento.com> Date: Mon, 8 Oct 2018 23:49:41 +0300 Subject: [PATCH 114/118] Fixed code style --- .../Api/Data/BulkSummaryInterface.php | 1 + .../AsynchronousOperations/Model/MassSchedule.php | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php index 9593cb983950a..a433ec0953a83 100644 --- a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php +++ b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php @@ -43,6 +43,7 @@ public function getUserType(); /** * Set user type + * * @param int $userType * @return $this */ diff --git a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php index 28a360adc5101..eae92e1663fc8 100644 --- a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php +++ b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php @@ -23,6 +23,8 @@ /** * Class MassSchedule used for adding multiple entities as Operations to Bulk Management with the status tracking + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) Suppressed without refactoring to not introduce BiC */ class MassSchedule { @@ -93,10 +95,10 @@ public function __construct( /** * Schedule new bulk operation based on the list of entities * - * @param $topicName - * @param $entitiesArray - * @param null $groupId - * @param null $userId + * @param string $topicName + * @param array $entitiesArray + * @param string $groupId + * @param string $userId * @return AsyncResponseInterface * @throws BulkException * @throws LocalizedException From 7acbb9aafc28472e6d5695a47de25e99003c3405 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 10 Oct 2018 13:23:47 +0300 Subject: [PATCH 115/118] MAGETWO-95215: [GraphQL] Performance issue in filters realization --- lib/internal/Magento/Framework/GraphQl/Query/Fields.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Fields.php b/lib/internal/Magento/Framework/GraphQl/Query/Fields.php index fb18fa1bfab8a..d0bc9591265eb 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/Fields.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/Fields.php @@ -21,7 +21,7 @@ class Fields private $fieldsUsedInQuery = []; /** - * Prints AST to string. Capable of printing GraphQL queries and Type definition language. + * Set Query for extracting list of fields. * * @param string $query * @return void @@ -42,6 +42,7 @@ public function setQuery($query) ] ); } catch (\Exception $e) { + // If a syntax error is encountered do not collect fields } if (isset($queryFields['IntrospectionQuery'])) { // It must be possible to query any fields during introspection query From 83426d778a09b995a3ee1d41b6505abfd0ab94d3 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote <khiserote@magento.com> Date: Wed, 10 Oct 2018 10:44:23 -0500 Subject: [PATCH 116/118] MAGETWO-91057: MFTF Test failure - Add products to wishlist from different stores - add testCaseId --- .../Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml index f8a1707e6c23a..b91f796e6a18f 100644 --- a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml +++ b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontAddMultipleStoreProductsToWishlistTest.xml @@ -15,6 +15,7 @@ <description value="All products added to wishlist should be visible on any store. Even if product visibility was set to 'Not Visible Individually' for this store"/> <group value="wishlist"/> <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-95678"/> </annotations> <before> <createData entity="customStoreGroup" stepKey="storeGroup"/> From ef60a4e44a6ea66d60d076734d0a86b85876664e Mon Sep 17 00:00:00 2001 From: Joan He <johe@adobe.com> Date: Thu, 11 Oct 2018 08:28:13 -0500 Subject: [PATCH 117/118] MAGETWO-94438: AdminAddImageToWYSIWYGProductTest is unstable --- .../Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml index 37c0eb6ea1253..d8f6bc3e4a749 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml @@ -16,6 +16,9 @@ <description value="Admin should be able to add image to WYSIWYG Editor on Product Page"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84375"/> + <skip> + <issueId value="MAGETWO-94438"/> + </skip> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="login"/> From 96498d0aa646b9ef6a3a61e0aa3b1c6d05811ecd Mon Sep 17 00:00:00 2001 From: Joan He <johe@adobe.com> Date: Fri, 12 Oct 2018 14:37:19 -0500 Subject: [PATCH 118/118] MAGETWO-60034: Cannot ship remaining items in an order for several of one product if credit memo is made for some - fix static test failure --- .../Constraint/AssertOrderCancelMassActionPartialFailMessage.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php index 6aed5cd39aaad..ecc9af83580f3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionPartialFailMessage.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Sales\Test\Constraint;