diff --git a/CHANGELOG.md b/CHANGELOG.md index ef841ec0337f2..078b93bd7199c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1977,7 +1977,7 @@ Tests: * [#686](https://github.com/magento/magento2/issues/686) -- Product save validation errors in the admin don't hide the overlay * [#702](https://github.com/magento/magento2/issues/702) -- Base table or view not found * [#652](https://github.com/magento/magento2/issues/652) -- Multishipping checkout not to change the Billing address js issue - * [#648](https://github.com/magento/magento2/issues/648) -- An equal (=) sign in the hash of the product page to to break the tabs functionality + * [#648](https://github.com/magento/magento2/issues/648) -- An equal (=) sign in the hash of the product page to break the tabs functionality * Service Contracts: * Refactored usage of new API of the Customer module * Implemented Service Contracts for the Sales module diff --git a/app/code/Magento/Backend/view/adminhtml/templates/page/header.phtml b/app/code/Magento/Backend/view/adminhtml/templates/page/header.phtml index 8feccc9cf1b8f..f952001f5e2ff 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/page/header.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/page/header.phtml @@ -17,7 +17,7 @@ class="logo"> <?= $block->escapeHtml(__('Magento Admin Panel')) ?> + alt="escapeHtml(__('Magento Admin Panel')) ?>" title="escapeHtml(__('Magento Admin Panel')) ?>"/> diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/form/element/gallery.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/form/element/gallery.phtml index 4f8d9a56a38a3..e11c0efc123ff 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/form/element/gallery.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/form/element/gallery.phtml @@ -34,7 +34,7 @@ getValues()->getAttributeBackend()->getImageTypes() as $type): ?> - <?= /* @escapeNotVerified */ $image->getValue() ?>
+ <?= /* @escapeNotVerified */ $image->getValue() ?>
diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml index 1cc0ce147ae0e..28fca883350e1 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml @@ -10,10 +10,10 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - + 1 - 1 + 0 1.11 1 1 diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml index 80d9307255e59..e10fe4e33c208 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml @@ -8,13 +8,34 @@ - + bundle-option-dropdown true - dropdown + select + 0 + + + + bundle-option-radio + true + radio 1 + + bundle-option-checkbox + true + checkbox + 3 + + + + bundle-option-multipleselect + true + multi + 4 + + diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml index 65ac763460151..380b5b8959025 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml @@ -19,4 +19,8 @@ price_view 1 + + price_view + 0 + diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml index 80ffe13ff3fe4..9c48b904bb7fd 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml @@ -45,4 +45,19 @@ CustomAttributeDynamicPrice CustomAttributePriceView + + Api Bundle Product + api-bundle-product + bundle + 4 + 4 + 1 + api-bundle-product + CustomAttributeCategoryIds + EavStockItem + ApiProductDescription + ApiProductShortDescription + CustomAttributeDynamicPrice + CustomAttributePriceViewRange + diff --git a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml index 435cf59c6cbfd..ca39253aa54a0 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml @@ -8,7 +8,7 @@ - + application/json string diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml new file mode 100644 index 0000000000000..c76f822a0913f --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml @@ -0,0 +1,15 @@ + + + + +
+ + +
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml new file mode 100644 index 0000000000000..41c00b5eda184 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -0,0 +1,17 @@ + + + + +
+ + + + +
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml new file mode 100644 index 0000000000000..1b1a46d1c8ba4 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml @@ -0,0 +1,237 @@ + + + + + + + + + <description value="Verify prices for various configurations of Dynamic Bundle product"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-43619"/> + <group value="bundle"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createSubCategory"/> + + <!--Create 5 simple product--> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"> + <field key="price">4.99</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"> + <field key="price">2.89</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct3"> + <field key="price">7.33</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct4"> + <field key="price">18.25</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct5"> + <field key="price">10.00</field> + </createData> + + <!--Add special price to simple product--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <amOnPage url="{{AdminProductEditPage.url($$simpleProduct5.id$$)}}" stepKey="openAdminEditPage"/> + <actionGroup ref="AddSpecialPriceToProductActionGroup" stepKey="addSpecialPrice"/> + <actionGroup ref="saveProductForm" stepKey="saveProductForm"/> + + <!--Create Bundle product--> + <createData entity="ApiBundleProductPriceViewRange" stepKey="createBundleProduct"> + <requiredEntity createDataKey="createSubCategory"/> + </createData> + <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> + <requiredEntity createDataKey="createBundleProduct"/> + <field key="required">false</field> + </createData> + <createData entity="CheckboxOption" stepKey="createBundleOption1_2"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct1"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct2"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct3"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct4"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct4"/> + </createData> + + <!--Create Bundle product 2--> + <createData entity="ApiBundleProductPriceViewRange" stepKey="createBundleProduct2"> + <requiredEntity createDataKey="createSubCategory"/> + </createData> + <createData entity="DropDownBundleOption" stepKey="createBundleOption2_1"> + <requiredEntity createDataKey="createBundleProduct2"/> + </createData> + <createData entity="RadioButtonsOption" stepKey="createBundleOption2_2"> + <requiredEntity createDataKey="createBundleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct5"> + <requiredEntity createDataKey="createBundleProduct2"/> + <requiredEntity createDataKey="createBundleOption2_1"/> + <requiredEntity createDataKey="simpleProduct1"/> + <field key="qty">2</field> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct6"> + <requiredEntity createDataKey="createBundleProduct2"/> + <requiredEntity createDataKey="createBundleOption2_1"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct7"> + <requiredEntity createDataKey="createBundleProduct2"/> + <requiredEntity createDataKey="createBundleOption2_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct8"> + <requiredEntity createDataKey="createBundleProduct2"/> + <requiredEntity createDataKey="createBundleOption2_2"/> + <requiredEntity createDataKey="simpleProduct4"/> + <field key="qty">5</field> + </createData> + + <!--Create Bundle product 3--> + <createData entity="ApiBundleProductPriceViewRange" stepKey="createBundleProduct3"> + <requiredEntity createDataKey="createSubCategory"/> + </createData> + <createData entity="MultipleSelectOption" stepKey="createBundleOption3_1"> + <requiredEntity createDataKey="createBundleProduct3"/> + </createData> + <createData entity="DropDownBundleOption" stepKey="createBundleOption3_2"> + <requiredEntity createDataKey="createBundleProduct3"/> + <field key="required">false</field> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct9"> + <requiredEntity createDataKey="createBundleProduct3"/> + <requiredEntity createDataKey="createBundleOption3_1"/> + <requiredEntity createDataKey="simpleProduct4"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct10"> + <requiredEntity createDataKey="createBundleProduct3"/> + <requiredEntity createDataKey="createBundleOption3_1"/> + <requiredEntity createDataKey="simpleProduct5"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct11"> + <requiredEntity createDataKey="createBundleProduct3"/> + <requiredEntity createDataKey="createBundleOption3_2"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct12"> + <requiredEntity createDataKey="createBundleProduct3"/> + <requiredEntity createDataKey="createBundleOption3_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + + <!-- navigate to the tax configuration page --> + <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToAdminTaxPage"/> + <waitForPageLoad stepKey="waitForTaxConfigLoad"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationSettings}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationSettingsOpened}}" visible="false" stepKey="openCalculationSettingsTab"/> + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationAlgorithmInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationAlgorithmDisabled}}" visible="true" stepKey="clickCalculationMethodBasedCheckBox"/> + <selectOption userInput="Total" selector="{{AdminConfigureTaxSection.taxCalculationAlgorithm}}" stepKey="fillCalculationMethodBased"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationBasedInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationBasedDisabled}}" visible="true" stepKey="clickTaxCalculationBasedCheckBox"/> + <selectOption userInput="Shipping Origin" selector="{{AdminConfigureTaxSection.taxCalculationBased}}" stepKey="fillTaxCalculationBased"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationPricesInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationPricesDisabled}}" visible="true" stepKey="clickCalculationPricesCheckBox"/> + <selectOption userInput="Excluding Tax" selector="{{AdminConfigureTaxSection.taxCalculationPrices}}" stepKey="clickCalculationPrices"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxPriceDisplaySettings}}" dependentSelector="{{AdminConfigureTaxSection.taxPriceDisplaySettingsOpened}}" visible="false" stepKey="openPriceDisplaySettings"/> + <conditionalClick selector="{{AdminConfigureTaxSection.taxDisplayProductPricesInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxDisplayProductPricesDisabled}}" visible="true" stepKey="clickDisplayProductPricesCheckBox"/> + <selectOption userInput="Excluding Tax" selector="{{AdminConfigureTaxSection.taxDisplayProductPrices}}" stepKey="clickDisplayProductPrices"/> + + <!-- Save the settings --> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveTaxOptions"/> + <waitForPageLoad stepKey="waitForTaxSaved"/> + <see userInput="You saved the configuration." selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccess"/> + + <magentoCLI command="indexer:reindex" stepKey="reindex"/> + </before> + <after> + <!-- navigate to the tax configuration page --> + <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToAdminTaxPage"/> + <waitForPageLoad stepKey="waitForTaxConfigLoad"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationSettings}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationSettingsOpened}}" visible="false" stepKey="openCalculationSettingsTab"/> + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationAlgorithmInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationAlgorithmDisabled}}" visible="true" stepKey="clickCalculationMethodBasedCheckBox"/> + <selectOption userInput="Total" selector="{{AdminConfigureTaxSection.taxCalculationAlgorithm}}" stepKey="fillCalculationMethodBased"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationBasedInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationBasedDisabled}}" visible="true" stepKey="clickTaxCalculationBasedCheckBox"/> + <selectOption userInput="Shipping Address" selector="{{AdminConfigureTaxSection.taxCalculationBased}}" stepKey="fillTaxCalculationBased"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationPricesInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationPricesDisabled}}" visible="true" stepKey="clickCalculationPricesCheckBox"/> + <selectOption userInput="Excluding Tax" selector="{{AdminConfigureTaxSection.taxCalculationPrices}}" stepKey="clickCalculationPrices"/> + + <conditionalClick selector="{{AdminConfigureTaxSection.taxPriceDisplaySettings}}" dependentSelector="{{AdminConfigureTaxSection.taxPriceDisplaySettingsOpened}}" visible="false" stepKey="openPriceDisplaySettings"/> + <conditionalClick selector="{{AdminConfigureTaxSection.taxDisplayProductPricesInherit}}" dependentSelector="{{AdminConfigureTaxSection.taxDisplayProductPricesDisabled}}" visible="true" stepKey="clickDisplayProductPricesCheckBox"/> + <selectOption userInput="Excluding Tax" selector="{{AdminConfigureTaxSection.taxDisplayProductPrices}}" stepKey="clickDisplayProductPrices"/> + + <!-- Save the settings --> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveTaxOptions"/> + <waitForPageLoad stepKey="waitForTaxSaved"/> + <see userInput="You saved the configuration." selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccess"/> + + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createSubCategory" stepKey="deleteSubCategory1"/> + + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <deleteData createDataKey="simpleProduct3" stepKey="deleteSimpleProduct3"/> + <deleteData createDataKey="simpleProduct4" stepKey="deleteSimpleProduct4"/> + <deleteData createDataKey="simpleProduct5" stepKey="deleteSimpleProduct5"/> + + <deleteData createDataKey="createBundleProduct" stepKey="deleteBundleProduct"/> + <deleteData createDataKey="createBundleProduct2" stepKey="deleteBundleProduct2"/> + <deleteData createDataKey="createBundleProduct3" stepKey="deleteBundleProduct3"/> + </after> + + <!-- Go to storefront category page --> + <amOnPage url="{{StorefrontCategoryPage.url($$createSubCategory.name$$)}}" stepKey="onCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + + <see userInput="From $7.33" selector="{{StorefrontCategoryProductSection.priceFromByProductId($$createBundleProduct.id$$)}}" stepKey="seePriceFromInCategoryBundle1"/> + <see userInput="To $33.46" selector="{{StorefrontCategoryProductSection.priceToByProductId($$createBundleProduct.id$$)}}" stepKey="seePriceToInCategoryBundle1"/> + + <see userInput="From $10.22" selector="{{StorefrontCategoryProductSection.priceFromByProductId($$createBundleProduct2.id$$)}}" stepKey="seePriceFromInCategoryBundle2"/> + <see userInput="To $101.23" selector="{{StorefrontCategoryProductSection.priceToByProductId($$createBundleProduct2.id$$)}}" stepKey="seePriceToInCategoryBundle2"/> + + <see userInput="From $8.00 Regular Price $10.00" selector="{{StorefrontCategoryProductSection.priceFromByProductId($$createBundleProduct3.id$$)}}" stepKey="seePriceFromInCategoryBundle3"/> + <see userInput="To $33.58 Regular Price $35.58" selector="{{StorefrontCategoryProductSection.priceToByProductId($$createBundleProduct3.id$$)}}" stepKey="seePriceToInCategoryBundle3"/> + + <!-- Go to storefront product pages --> + <amOnPage url="{{StorefrontProductPage.url($$createBundleProduct.custom_attributes[url_key]$$)}}" stepKey="onPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <see userInput="From $7.33" selector="{{StorefrontProductInfoMainSection.priceFrom}}" stepKey="seePriceFromBundle1"/> + <see userInput="To $33.46" selector="{{StorefrontProductInfoMainSection.priceTo}}" stepKey="seePriceToBundle1"/> + + <amOnPage url="{{StorefrontProductPage.url($$createBundleProduct2.custom_attributes[url_key]$$)}}" stepKey="onPageBundle2"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <see userInput="From $10.22" selector="{{StorefrontProductInfoMainSection.priceFrom}}" stepKey="seePriceFromBundle2"/> + <see userInput="To $101.23" selector="{{StorefrontProductInfoMainSection.priceTo}}" stepKey="seePriceToBundle2"/> + + <amOnPage url="{{StorefrontProductPage.url($$createBundleProduct3.custom_attributes[url_key]$$)}}" stepKey="onPageBundle3"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <see userInput="From $8.00 Regular Price $10.00" selector="{{StorefrontProductInfoMainSection.priceFrom}}" stepKey="seePriceFromBundle3"/> + <see userInput="To $33.58 Regular Price $35.58" selector="{{StorefrontProductInfoMainSection.priceTo}}" stepKey="seePriceToBundle3"/> + </test> +</tests> diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php index 09dbed350c5e4..f8121b55dbf99 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php @@ -8,6 +8,7 @@ use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher; use Magento\Framework\DB\Query\Generator as QueryGenerator; use Magento\Framework\App\ResourceConnection; +use Magento\Indexer\Model\ProcessManager; /** * Class Full reindex action @@ -44,6 +45,11 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio */ private $activeTableSwitcher; + /** + * @var ProcessManager + */ + private $processManager; + /** * @param ResourceConnection $resource * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -52,9 +58,10 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio * @param \Magento\Framework\Indexer\BatchSizeManagementInterface|null $batchSizeManagement * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool - * @param \Magento\Indexer\Model\Indexer\StateFactory|null $stateFactory * @param int|null $batchRowsCount * @param ActiveTableSwitcher|null $activeTableSwitcher + * @param ProcessManager $processManager + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\App\ResourceConnection $resource, @@ -65,7 +72,8 @@ public function __construct( \Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null, \Magento\Framework\EntityManager\MetadataPool $metadataPool = null, $batchRowsCount = null, - ActiveTableSwitcher $activeTableSwitcher = null + ActiveTableSwitcher $activeTableSwitcher = null, + ProcessManager $processManager = null ) { parent::__construct( $resource, @@ -85,6 +93,7 @@ public function __construct( ); $this->batchRowsCount = $batchRowsCount; $this->activeTableSwitcher = $activeTableSwitcher ?: $objectManager->get(ActiveTableSwitcher::class); + $this->processManager = $processManager ?: $objectManager->get(ProcessManager::class); } /** @@ -133,6 +142,38 @@ public function execute() return $this; } + /** + * Run reindexation + * + * @return void + */ + protected function reindex() + { + $userFunctions = []; + + foreach ($this->storeManager->getStores() as $store) { + if ($this->getPathFromCategoryId($store->getRootCategoryId())) { + $userFunctions[$store->getId()] = function () use ($store) { + return $this->reindexStore($store); + }; + } + } + + $this->processManager->execute($userFunctions); + } + + /** + * Execute indexation by store + * + * @param \Magento\Store\Model\Store $store + */ + private function reindexStore($store) + { + $this->reindexRootCategory($store); + $this->reindexAnchorCategories($store); + $this->reindexNonAnchorCategories($store); + } + /** * Publish data from tmp to replica table * diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index f64812fd5bf49..bca6ae2b60bf3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -181,6 +181,19 @@ </arguments> <conditionalClick selector="{{AdminProductFormSection.productFormTab('Related Products')}}" dependentSelector="{{AdminProductFormSection.productFormTabState('Related Products', 'closed')}}" visible="true" stepKey="openTab"/> <waitForPageLoad time="30" stepKey="waitForPageLoad"/> - <see selector="{{element}}" userInput="{{expectedText}}" stepKey="AssertText"/> + <see selector="{{element}}" userInput="{{expectedText}}" stepKey="assertText"/> </actionGroup> + + <!--Add special price to product in Admin product page--> + <actionGroup name="AddSpecialPriceToProductActionGroup"> + <arguments> + <argument name="price" type="string" defaultValue="8"/> + </arguments> + <waitForPageLoad stepKey="waitForPageLoad"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickAdvancedPricingLink"/> + <waitForElementVisible selector="{{AdminProductFormAdvancedPricingSection.specialPrice}}" stepKey="waitSpecialPrice"/> + <fillField userInput="{{price}}" selector="{{AdminProductFormAdvancedPricingSection.specialPrice}}" stepKey="fillSpecialPrice"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDone"/> + <waitForElementNotVisible selector="{{AdminProductFormAdvancedPricingSection.specialPrice}}" stepKey="waitForCloseModalWindow"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml index 35fa00efcfe8e..be7c44e378f08 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductCreatePage.xml @@ -16,5 +16,6 @@ <section name="AdminAddProductsToOptionPanel"/> <section name="AdminProductMessagesSection"/> <section name="AdminProductFormRelatedUpSellCrossSellSection"/> + <section name="AdminProductFormAdvancedPricingSection"/> </page> </pages> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml new file mode 100644 index 0000000000000..1042b1e5a5464 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml @@ -0,0 +1,25 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminProductFormAdvancedPricingSection"> + <element name="customerGroupPriceAddButton" type="button" selector="[data-action='add_new_row']" timeout="30"/> + <element name="customerGroupPriceDeleteButton" type="button" selector="[data-action='remove_row']" timeout="30"/> + <element name="advancedPricingCloseButton" type="button" selector=".product_form_product_form_advanced_pricing_modal button.action-close" timeout="30"/> + <element name="productTierPriceWebsiteSelect" type="select" selector="[name='product[tier_price][{{var1}}][website_id]']" parameterized="true"/> + <element name="productTierPriceCustGroupSelect" type="select" selector="[name='product[tier_price][{{var1}}][cust_group]']" parameterized="true"/> + <element name="productTierPriceQtyInput" type="input" selector="[name='product[tier_price][{{var1}}][price_qty]']" parameterized="true"/> + <element name="productTierPriceValueTypeSelect" type="select" selector="[name='product[tier_price][{{var1}}][value_type]']" parameterized="true"/> + <element name="productTierPriceFixedPriceInput" type="input" selector="[name='product[tier_price][{{var1}}][price]']" parameterized="true"/> + <element name="productTierPricePercentageValuePriceInput" type="input" selector="[name='product[tier_price][{{var1}}][percentage_value]']" parameterized="true"/> + <element name="specialPrice" type="input" selector="input[name='product[special_price]']"/> + <element name="doneButton" type="button" selector=".product_form_product_form_advanced_pricing_modal button.action-primary" timeout="5"/> + <element name="save" type="button" selector="#save-button"/> + </section> +</sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml index 4892e25818e2c..19b3a5cc127a7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml @@ -23,6 +23,10 @@ <element name="ProductImageByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//img[@class='product-image-photo']" parameterized="true"/> <element name="ProductImageBySrc" type="text" selector=".products-grid img[src*='{{pattern}}']" parameterized="true"/> <element name="ProductInfoByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//div[@class='product-item-info']" parameterized="true"/> + <element name="productPriceFinal" type="text" selector="//span[@data-price-type='finalPrice']//span[@class='price'][contains(.,'{{var1}}')]" parameterized="true"/> + <element name="productPriceOld" type="text" selector="//span[@data-price-type='oldPrice']//span[@class='price'][contains(., '{{var1}}')]" parameterized="true"/> + <element name="productPriceLabel" type="text" selector="//span[@class='price-label'][contains(text(),'{{var1}}')]" parameterized="true"/> + <element name="productPriceLinkAfterLabel" type="text" selector="//span[@class='price-label'][contains(text(),'{{var1}}')]/following::span[contains(text(), '{{var2}}')]" parameterized="true"/> <element name="ProductAddToCartByName" type="button" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//a[contains(@class, 'tocart')]" parameterized="true"/> <element name="ProductAddToCompareByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//a[contains(@class, 'tocompare')]" parameterized="true"/> <element name="ProductImageByNameAndSrc" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//img[contains(@src, '{{src}}')]" parameterized="true"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index 7e1bec48aeebc..42ca3836e6c1c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -14,6 +14,7 @@ <element name="productSku" type="text" selector=".product.attribute.sku>.value"/> <element name="productPriceLabel" type="text" selector=".price-label"/> <element name="productPrice" type="text" selector="div.price-box.price-final_price"/> + <element name="qty" type="input" selector="#qty"/> <element name="specialPrice" type="text" selector=".special-price"/> <element name="updatedPrice" type="text" selector="div.price-box.price-final_price [data-price-type='finalPrice'] .price"/> <element name="oldPrice" type="text" selector=".old-price"/> @@ -63,5 +64,10 @@ <element name="productAddToCompare" type="button" selector="a.action.tocompare"/> <element name="productOptionDropDownTitle" type="text" selector="//label[contains(.,'{{var1}}')]" parameterized="true"/> <element name="productOptionDropDownOptionTitle" type="text" selector="//label[contains(.,'{{var1}}')]/../div[@class='control']//select//option[contains(.,'{{var2}}')]" parameterized="true"/> + + <!-- Tier price selectors --> + <element name="productTierPriceByForTextLabel" type="text" selector="//ul[contains(@class, 'prices-tier')]//li[{{var1}}][contains(text(),'Buy {{var2}} for')]" parameterized="true"/> + <element name="productTierPriceAmount" type="text" selector="//ul[contains(@class, 'prices-tier')]//li[{{var1}}]//span[contains(text(), '{{var2}}')]" parameterized="true"/> + <element name="productTierPriceSavePercentageAmount" type="text" selector="//ul[contains(@class, 'prices-tier')]//li[{{var1}}]//span[contains(@class, 'percent')][contains(text(), '{{var2}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest.xml new file mode 100644 index 0000000000000..902f51c4a15a7 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest.xml @@ -0,0 +1,271 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminApplyTierPriceToProductTest"> + <annotations> + <features value="Apply tier price to a product"/> + <title value="You should be able to apply tier price to a product."/> + <description value="You should be able to apply tier price to a product."/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-68921"/> + <group value="product"/> + </annotations> + <before> + <createData entity="Simple_US_Customer" stepKey="createSimpleUSCustomer"> + <field key="group_id">1</field> + </createData> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + <field key="price">100</field> + </createData> + </before> + <after> + <deleteData createDataKey="createSimpleUSCustomer" stepKey="deleteCustomer"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex1"/> + <waitForPageLoad time="30" stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetGridToDefaultKeywordSearch"/> + <actionGroup ref="logout" stepKey="logoutFromAdmin"/> + </after> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <!--Case: Group Price--> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct1"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfPage1"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton1"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForCustomerGroupPriceAddButton1"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAnd10percent"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" userInput="1" stepKey="fillProductTierPriceQtyInput1"/> + <selectOption selector="{{AdminProductFormAdvancedPricingSection.productTierPriceValueTypeSelect('0')}}" userInput="Discount" stepKey="selectProductTierPriceValueType1"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" userInput="10" stepKey="selectProductTierPricePriceInput"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton1"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct1"/> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin1"> + <argument name="Customer" value="$$createSimpleUSCustomer$$" /> + </actionGroup> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('90')}}" stepKey="assertProductFinalPriceIs90_1"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('Regular Price')}}" stepKey="assertRegularPriceLabel_1"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceOld('100')}}" stepKey="assertRegularPriceAmount_1"/> + <amOnPage url="customer/account/logout/" stepKey="logoutCustomer1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage2"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad3"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('90')}}" stepKey="assertProductFinalPriceIs90_2"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('Regular Price')}}" stepKey="assertRegularPriceLabel_2"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceOld('100')}}" stepKey="assertRegularPriceAmount_2"/> + <!--Case: Tier Price for General Customer Group--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex2"/> + <waitForPageLoad time="30" stepKey="waitForProductPageToLoad1"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct2"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfPage2"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton2"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForcustomerGroupPriceAddButton2"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.productTierPriceCustGroupSelect('0')}}" time="30" stepKey="waitForSelectCustomerGroupNameAttribute1"/> + <selectOption selector="{{AdminProductFormAdvancedPricingSection.productTierPriceCustGroupSelect('0')}}" userInput="General" stepKey="selectCustomerGroupGeneral"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton2"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct2"/> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage3"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad4"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('100')}}" stepKey="assertProductFinalPriceIs100_1"/> + <dontSeeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('Regular Price')}}" stepKey="assertRegularPriceLabel_3"/> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin2"> + <argument name="Customer" value="$$createSimpleUSCustomer$$" /> + </actionGroup> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage4"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('90')}}" stepKey="assertProductFinalPriceIs90_3"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('Regular Price')}}" stepKey="assertRegularPriceLabel_4"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceOld('100')}}" stepKey="assertRegularPriceAmount_3"/> + <!--Case: Tier Price applied if Product quantity meets Tier Price Condition--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex3"/> + <waitForPageLoad time="30" stepKey="waitForProductPageToLoad2"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct3"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfPage3"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton3"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForcustomerGroupPriceAddButton3"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.productTierPriceCustGroupSelect('0')}}" stepKey="waitForSelectCustomerGroupNameAttribute2"/> + <selectOption selector="{{AdminProductFormAdvancedPricingSection.productTierPriceCustGroupSelect('0')}}" userInput="ALL GROUPS" stepKey="selectCustomerGroupAllGroups"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" userInput="15" stepKey="fillProductTierPriceQtyInput15"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="clickToLoseFocusOnRequiredInputElement"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="addCustomerGroupAllGroupsQty20PriceDiscountAnd18percent2"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('1')}}" userInput="20" stepKey="fillProductTierPriceQtyInput20"/> + <selectOption selector="{{AdminProductFormAdvancedPricingSection.productTierPriceValueTypeSelect('1')}}" userInput="Discount" stepKey="selectProductTierPriceValueType2"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('1')}}" userInput="18" stepKey="selectProductTierPricePriceInput18"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton3"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct3"/> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage5"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad6"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('100')}}" stepKey="assertProductFinalPriceIs100_2"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('As low as')}}" stepKey="assertAsLowAsPriceLabel_1"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLinkAfterLabel('As low as', '82')}}" stepKey="assertPriceAfterAsLowAsLabel_1"/> + <amOnPage url="customer/account/logout/" stepKey="logoutCustomer2"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad7"/> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage6"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad8"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('100')}}" stepKey="assertProductFinalPriceIs100_3"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('As low as')}}" stepKey="assertAsLowAsPriceLabel_2"/> + <seeElement selector="{{StorefrontCategoryProductSection.productPriceLinkAfterLabel('As low as', '82')}}" stepKey="assertPriceAfterAsLowAsLabel_2"/> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="goToProductPage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad9"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceByForTextLabel('1', '15')}}" stepKey="assertProductTierPriceByForTextLabelForFirstRow1"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceByForTextLabel('2', '20')}}" stepKey="assertProductTierPriceByForTextLabelForSecondRow1"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceAmount('1', '90')}}" stepKey="assertProductTierPriceAmountForFirstRow1"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceAmount('2', '82')}}" stepKey="assertProductTierPriceAmountForSecondRow1"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceSavePercentageAmount('1', '10')}}" stepKey="assertProductTierPriceSavePercentageAmountForFirstRow1"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceSavePercentageAmount('2', '18')}}" stepKey="assertProductTierPriceSavePercentageAmountForSecondRow1"/> + <fillField userInput="10" selector="{{StorefrontProductInfoMainSection.qty}}" stepKey="fillProductQuantity1"/> + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$$createSimpleProduct.name$$"/> + </actionGroup> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToCheckoutFromMinicart"/> + <seeInField userInput="10" selector="{{CheckoutCartProductSection.ProductQuantityByName($$createSimpleProduct.name$$)}}" stepKey="seeInQtyField10"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField1"/> + <assertEquals message="Shopping cart should contain subtotal $1,000" stepKey="assertSubtotalField1"> + <expectedResult type="string">$1,000.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField1</actualResult> + </assertEquals> + <fillField userInput="15" selector="{{CheckoutCartProductSection.ProductQuantityByName($$createSimpleProduct.name$$)}}" stepKey="fillProductQuantity2"/> + <click selector="{{CheckoutCartProductSection.updateShoppingCartButton}}" stepKey="clickUpdateShoppingCartButton1"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField2"/> + <assertEquals message="Shopping cart should contain subtotal $1,350" stepKey="assertSubtotalField2"> + <expectedResult type="string">$1,350.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField2</actualResult> + </assertEquals> + <fillField userInput="20" selector="{{CheckoutCartProductSection.ProductQuantityByName($$createSimpleProduct.name$$)}}" stepKey="fillProductQuantity3"/> + <click selector="{{CheckoutCartProductSection.updateShoppingCartButton}}" stepKey="clickUpdateShoppingCartButton2"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear2"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField3"/> + <assertEquals message="Shopping cart should contain subtotal $1,640" stepKey="assertSubtotalField3"> + <expectedResult type="string">$1,640.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField3</actualResult> + </assertEquals> + <!--Tier Price is changed in Shopping Cart and is changed on Product page if Tier Price parameters are changed in Admin--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex4"/> + <waitForPageLoad time="30" stepKey="waitForProductPageToLoa4"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct4"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfPage4"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton4"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForcustomerGroupPriceAddButton4"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('1')}}" userInput="25" stepKey="selectProductTierPricePercentageValue2"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton4"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct4"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToShoppingCartPage1"/> + <waitForPageLoad time="30" stepKey="waitForShoppingCartPagePageLoad1"/> + <seeInField userInput="20" selector="{{CheckoutCartProductSection.ProductQuantityByName($$createSimpleProduct.name$$)}}" stepKey="seeInQtyField20"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField4"/> + <assertEquals message="Shopping cart should contain subtotal $1,500" stepKey="assertSubtotalField4"> + <expectedResult type="string">$1,500.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField4</actualResult> + </assertEquals> + <grabTextFrom selector="{{CheckoutCartSummarySection.subtotal}}" stepKey="grabTextFromCheckoutCartSummarySectionSubtotal1"/> + <assertEquals message="Shopping cart summary section should contain subtotal $1,500" stepKey="assertSubtotalFieldFromCheckoutCartSummarySection1"> + <expectedResult type="string">$1,500.00</expectedResult> + <actualResult type="variable">grabTextFromCheckoutCartSummarySectionSubtotal1</actualResult> + </assertEquals> + <conditionalClick selector="{{StorefrontMinicartSection.showCart}}" dependentSelector="{{StorefrontMinicartSection.miniCartOpened}}" visible="false" stepKey="openMiniCart1"/> + <waitForElementVisible selector="{{StorefrontMinicartSection.miniCartSubtotalField}}" stepKey="waitForminiCartSubtotalField1"/> + <grabTextFrom selector="{{StorefrontMinicartSection.miniCartSubtotalField}}" stepKey="grabTextFromMiniCartSubtotalField"/> + <assertEquals message="Mini shopping cart should contain subtotal $1,500" stepKey="assertSubtotalFieldFromMiniShoppingCart1"> + <expectedResult type="string">$1,500.00</expectedResult> + <actualResult type="variable">grabTextFromMiniCartSubtotalField</actualResult> + </assertEquals> + <amOnPage url="{{AdminSalesConfigPage.url('#sales_msrp-link')}}" stepKey="navigateToAdminSalesConfigPageMAPTab1"/> + <waitForPageLoad time="30" stepKey="waitForAdminSalesConfigPageLoad1"/> + <uncheckOption selector="{{AdminSalesConfigSection.enableMAPUseSystemValue}}" stepKey="uncheckMAPUseSystemValue"/> + <selectOption selector="{{AdminSalesConfigSection.enableMAPSelect}}" userInput="Yes" stepKey="setEnableMAPYes"/> + <click selector="{{AdminConfigSection.saveButton}}" stepKey="saveConfig1"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the configuration." stepKey="seeConfigSuccessMessage1"/> + <actionGroup ref="ClearCacheActionGroup" stepKey="flushCache1"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToShoppingCartPage2"/> + <waitForPageLoad time="30" stepKey="waitForShoppingCartPagePageLoad2"/> + <seeInField userInput="20" selector="{{CheckoutCartProductSection.ProductQuantityByName($$createSimpleProduct.name$$)}}" stepKey="seeInQtyField20_2"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField5"/> + <assertEquals message="Shopping cart should contain subtotal $1,500" stepKey="assertSubtotalField5"> + <expectedResult type="string">$1,500.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField5</actualResult> + </assertEquals> + <amOnPage url="{{AdminSalesConfigPage.url('#sales_msrp-link')}}" stepKey="navigateToAdminSalesConfigPageMAPTab2"/> + <waitForPageLoad time="30" stepKey="waitForAdminSalesConfigPageLoad2"/> + <selectOption selector="{{AdminSalesConfigSection.enableMAPSelect}}" userInput="No" stepKey="setEnableMAPNo"/> + <click selector="{{AdminConfigSection.saveButton}}" stepKey="saveConfig2"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the configuration." stepKey="seeConfigSuccessMessage2"/> + <actionGroup ref="ClearCacheActionGroup" stepKey="flushCache2"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToShoppingCartPage3"/> + <waitForPageLoad time="30" stepKey="waitForShoppingCartPagePageLoad3"/> + <seeInField userInput="20" selector="{{CheckoutCartProductSection.ProductQuantityByName($$createSimpleProduct.name$$)}}" stepKey="seeInQtyField20_3"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField6"/> + <assertEquals message="Shopping cart should contain subtotal $1,500" stepKey="assertSubtotalField6"> + <expectedResult type="string">$1,500.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField6</actualResult> + </assertEquals> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="goToProductPage2"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad10"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceByForTextLabel('1', '15')}}" stepKey="assertProductTierPriceByForTextLabelForFirstRow2"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceByForTextLabel('2', '20')}}" stepKey="assertProductTierPriceByForTextLabelForSecondRow2"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceAmount('1', '90')}}" stepKey="assertProductTierPriceAmountForFirstRow2"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceAmount('2', '75')}}" stepKey="assertProductTierPriceAmountForSecondRow2"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceSavePercentageAmount('1', '10')}}" stepKey="assertProductTierPriceSavePercentageAmountForFirstRow2"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productTierPriceSavePercentageAmount('2', '25')}}" stepKey="assertProductTierPriceSavePercentageAmountForSecondRow2"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex5"/> + <waitForPageLoad time="30" stepKey="waitForProductPageToLoad3"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct5"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfPage5"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton5"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceDeleteButton}}" stepKey="waitForcustomerGroupPriceDeleteButton"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceDeleteButton}}" stepKey="deleteFirstRowOfCustomerGroupPrice"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceDeleteButton}}" stepKey="deleteSecondRowOfCustomerGroupPrice"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton5"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct5"/> + <scrollToTopOfPage stepKey="scrollToTopOfPage6"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton6"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForcustomerGroupPriceAddButton5"/> + <dontSeeElement selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" stepKey="dontSeeQtyInputOfFirstRow"/> + <dontSeeElement selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('1')}}" stepKey="dontSeeQtyInputOfSecondRow"/> + <click selector="{{AdminProductFormAdvancedPricingSection.advancedPricingCloseButton}}" stepKey="closeAdvancedPricingPopup"/> + <waitForElementVisible selector="{{AdminProductFormSection.productPrice}}" stepKey="waitForAdminProductFormSectionProductPriceInput"/> + <fillField selector="{{AdminProductFormSection.productPrice}}" userInput="200" stepKey="fillProductPrice200"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveButton"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToShoppingCartPage4"/> + <waitForPageLoad time="30" stepKey="waitForShoppingCartPagePageLoad4"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productSubtotalByName($$createSimpleProduct.name$$)}}" stepKey="grabTextFromSubtotalField7"/> + <assertEquals message="Shopping cart should contain subtotal $4,000" stepKey="assertSubtotalField7"> + <expectedResult type="string">$4,000.00</expectedResult> + <actualResult type="variable">grabTextFromSubtotalField7</actualResult> + </assertEquals> + <grabTextFrom selector="{{CheckoutCartSummarySection.subtotal}}" stepKey="grabTextFromCheckoutCartSummarySectionSubtotal2"/> + <assertEquals message="Shopping cart summary section should contain subtotal $4,000" stepKey="assertSubtotalFieldFromCheckoutCartSummarySection2"> + <expectedResult type="string">$4,000.00</expectedResult> + <actualResult type="variable">grabTextFromCheckoutCartSummarySectionSubtotal2</actualResult> + </assertEquals> + <conditionalClick selector="{{StorefrontMinicartSection.showCart}}" dependentSelector="{{StorefrontMinicartSection.miniCartOpened}}" visible="false" stepKey="openMiniCart2"/> + <waitForElementVisible selector="{{StorefrontMinicartSection.miniCartSubtotalField}}" stepKey="waitForminiCartSubtotalField2"/> + <grabTextFrom selector="{{StorefrontMinicartSection.miniCartSubtotalField}}" stepKey="grabTextFromMiniCartSubtotalField2"/> + <assertEquals message="Mini shopping cart should contain subtotal $4,000" stepKey="assertSubtotalFieldFromMiniShoppingCart2"> + <expectedResult type="string">$4,000.00</expectedResult> + <actualResult type="variable">grabTextFromMiniCartSubtotalField2</actualResult> + </assertEquals> + </test> +</tests> diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml index 16a5147e13458..adf0f44d0c831 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml @@ -6,7 +6,7 @@ // @codingStandardsIgnoreFile -/** @var $block \Magento\Catalog\Block\Catalog\Product\View\Addto\Compare */ +/** @var $block \Magento\Catalog\Block\Product\View\Addto\Compare */ ?> <a href="#" data-post='<?= /* @escapeNotVerified */ $block->getPostDataParams() ?>' diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php index da457279728bb..d2fc174fb1ed5 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php @@ -100,7 +100,7 @@ public function getTree(ResolveInfo $resolveInfo, int $rootCategoryId) : array $collection->addFieldToFilter('level', ['lteq' => $level + $depth - self::DEPTH_OFFSET]); $collection->setOrder('level'); $collection->getSelect()->orWhere( - $this->metadata->getMetadata(CategoryInterface::class)->getLinkField() . ' = ?', + $this->metadata->getMetadata(CategoryInterface::class)->getIdentifierField() . ' = ?', $rootCategoryId ); return $this->processTree($collection->getIterator()); diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php index d51be12f01db5..df9eb6e78990a 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php @@ -10,10 +10,13 @@ use Magento\CatalogSearch\Model\ResourceModel\Fulltext as FulltextResource; use Magento\Framework\Indexer\Dimension\DimensionProviderInterface; use Magento\Store\Model\StoreDimensionProvider; +use Magento\Indexer\Model\ProcessManager; /** * Provide functionality for Fulltext Search indexing. * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * * @api * @since 100.0.2 */ @@ -62,14 +65,20 @@ class Fulltext implements */ private $dimensionProvider; + /** + * @var ProcessManager + */ + private $processManager; + /** * @param FullFactory $fullActionFactory * @param IndexerHandlerFactory $indexerHandlerFactory * @param FulltextResource $fulltextResource - * @param array $data * @param IndexSwitcherInterface $indexSwitcher * @param StateFactory $indexScopeStateFactory * @param DimensionProviderInterface $dimensionProvider + * @param array $data + * @param ProcessManager $processManager */ public function __construct( FullFactory $fullActionFactory, @@ -78,7 +87,8 @@ public function __construct( IndexSwitcherInterface $indexSwitcher, StateFactory $indexScopeStateFactory, DimensionProviderInterface $dimensionProvider, - array $data + array $data, + ProcessManager $processManager = null ) { $this->fullAction = $fullActionFactory->create(['data' => $data]); $this->indexerHandlerFactory = $indexerHandlerFactory; @@ -87,6 +97,9 @@ public function __construct( $this->indexSwitcher = $indexSwitcher; $this->indexScopeState = $indexScopeStateFactory->create(); $this->dimensionProvider = $dimensionProvider; + $this->processManager = $processManager ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + ProcessManager::class + ); } /** @@ -145,9 +158,13 @@ public function executeByDimension(array $dimensions, \Traversable $entityIds = */ public function executeFull() { + $userFunctions = []; foreach ($this->dimensionProvider->getIterator() as $dimension) { - $this->executeByDimension($dimension); + $userFunctions[] = function () use ($dimension) { + $this->executeByDimension($dimension); + }; } + $this->processManager->execute($userFunctions); } /** diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php index 0c3bd42a1b5eb..595e32b4c1988 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php @@ -44,6 +44,11 @@ class FulltextTest extends \PHPUnit\Framework\TestCase */ private $dimensionProviderMock; + /** + * @var \Magento\Indexer\Model\ProcessManager|\PHPUnit_Framework_MockObject_MockObject + */ + private $processManager; + protected function setUp() { $this->fullAction = $this->getClassMock(\Magento\CatalogSearch\Model\Indexer\Fulltext\Action\Full::class); @@ -70,6 +75,11 @@ protected function setUp() $stateMock = $this->getMockBuilder(\Magento\CatalogSearch\Model\Indexer\Scope\State::class) ->getMock(); $objectManagerHelper = new ObjectManagerHelper($this); + + $this->processManager = new \Magento\Indexer\Model\ProcessManager( + $this->getClassMock(\Magento\Framework\App\ResourceConnection::class) + ); + $this->model = $objectManagerHelper->getObject( \Magento\CatalogSearch\Model\Indexer\Fulltext::class, [ @@ -80,6 +90,7 @@ protected function setUp() 'indexSwitcher' => $this->indexSwitcher, 'dimensionProvider' => $this->dimensionProviderMock, 'indexScopeState' => $stateMock, + 'processManager' => $this->processManager, ] ); } diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json index 72bf2ec90a582..298511ef428a9 100644 --- a/app/code/Magento/CatalogSearch/composer.json +++ b/app/code/Magento/CatalogSearch/composer.json @@ -9,6 +9,7 @@ "magento/framework": "*", "magento/module-backend": "*", "magento/module-catalog": "*", + "magento/module-indexer": "100.2.*", "magento/module-catalog-inventory": "*", "magento/module-customer": "*", "magento/module-directory": "*", diff --git a/app/code/Magento/CatalogSearch/etc/module.xml b/app/code/Magento/CatalogSearch/etc/module.xml index 68253014ec150..8fe282ce7539b 100644 --- a/app/code/Magento/CatalogSearch/etc/module.xml +++ b/app/code/Magento/CatalogSearch/etc/module.xml @@ -10,6 +10,7 @@ <sequence> <module name="Magento_Search"/> <module name="Magento_Catalog"/> + <module name="Magento_Indexer"/> <module name="Magento_CatalogRule" /> <module name="Magento_CatalogInventory" /> </sequence> diff --git a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutCartPage.xml b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutCartPage.xml index dcc652829b3cc..433d397ee81a9 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutCartPage.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutCartPage.xml @@ -8,7 +8,7 @@ <pages 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/PageObject.xsd"> - <page name="CheckoutCartPage" url="/checkout/cart" module="Checkout" area="storefront"> + <page name="CheckoutCartPage" url="/checkout/cart" module="Magento_Checkout" area="storefront"> <section name="CheckoutCartProductSection"/> <section name="CheckoutCartSummarySection"/> </page> diff --git a/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml new file mode 100644 index 0000000000000..59c3b20aca674 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Page/CheckoutShippingPage.xml @@ -0,0 +1,15 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="CheckoutShippingPage" url="/checkout/#shipping" module="Checkout" area="storefront"> + <section name="CheckoutShippingGuestInfoSection"/> + <section name="CheckoutShippingSection"/> + </page> +</pages> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml index 6e2262d58b89d..b3e3f082319fb 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml @@ -29,5 +29,7 @@ <element name="nthItemOption" type="block" selector=".item:nth-of-type({{numElement}}) .item-options" parameterized="true"/> <element name="nthEditButton" type="block" selector=".item:nth-of-type({{numElement}}) .action-edit" parameterized="true"/> <element name="nthBundleOptionName" type="text" selector=".product-item-details .item-options:nth-of-type({{numOption}}) dt" parameterized="true"/> + <element name="productSubtotalByName" type="input" selector="//main//table[@id='shopping-cart-table']//tbody//tr[..//strong[contains(@class, 'product-item-name')]//a/text()='{{var1}}'][1]//td[contains(@class, 'subtotal')]//span[@class='price']" parameterized="true"/> + <element name="updateShoppingCartButton" type="button" selector="#form-validate button[type='submit'].update" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml index ce4069a0c916d..01b483c8ecf0b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml @@ -16,8 +16,10 @@ <element name="proceedToCheckout" type="button" selector=".action.primary.checkout span" timeout="30"/> <element name="discountAmount" type="text" selector="td[data-th='Discount']"/> <element name="shippingHeading" type="button" selector="#block-shipping-heading"/> - <element name="postcode" type="input" selector="input[name='postcode']"/> - <element name="stateProvince" type="select" selector="select[name='region_id']"/> - <element name="country" type="select" selector="select[name='country_id']"/> + <element name="postcode" type="input" selector="input[name='postcode']" timeout="10"/> + <element name="stateProvince" type="select" selector="select[name='region_id']" timeout="10"/> + <element name="country" type="select" selector="select[name='country_id']" timeout="10"/> + <element name="estimateShippingAndTax" type="text" selector="#block-shipping-heading" timeout="5"/> + <element name="flatRateShippingMethod" type="radio" selector="#s_method_flatrate_flatrate" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml index 0da16a34134b8..faee71a54a0be 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml @@ -23,6 +23,7 @@ <element name="viewAndEditCart" type="button" selector=".action.viewcart" timeout="30"/> <element name="miniCartItemsText" type="text" selector=".minicart-items"/> <element name="deleteMiniCartItem" type="button" selector=".action.delete" timeout="30"/> + <element name="miniCartSubtotalField" type="text" selector=".block-minicart .amount span.price"/> <element name="itemQuantity" type="input" selector="//a[text()='{{productName}}']/../..//input[contains(@class,'cart-item-qty')]" parameterized="true"/> <element name="itemQuantityUpdate" type="button" selector="//a[text()='{{productName}}']/../..//span[text()='Update']" parameterized="true"/> </section> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml new file mode 100644 index 0000000000000..4b8d48a84073a --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml @@ -0,0 +1,59 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest"> + <annotations> + <features value="Checkout"/> + <title value="Guest Checkout"/> + <description value="Address State Field For UK Customers Remain Option even After Browser Refresh"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-93329"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + </after> + + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> + <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> + <see selector="{{StorefrontMinicartSection.quantity}}" userInput="1" stepKey="seeCartQuantity"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="guestGoToCheckoutFromMinicart" /> + <selectOption stepKey="selectCounty" selector="{{CheckoutShippingSection.country}}" userInput="{{UK_Address.country_id}}"/> + <waitForPageLoad stepKey="waitFormToReload"/> + <reloadPage stepKey="refreshPage"/> + <waitForPageLoad stepKey="waitFormToReload1"/> + <fillField selector="{{CheckoutShippingSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="enterEmail"/> + <fillField selector="{{CheckoutShippingSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutShippingSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutShippingSection.street}}" userInput="{{UK_Address.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutShippingSection.city}}" userInput="{{UK_Address.city}}" stepKey="enterCity"/> + <waitForPageLoad stepKey="waitFormToReload2"/> + <see userInput="State/Province" stepKey="StateFieldStillExists"/> + <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{UK_Address.telephone}}" stepKey="enterTelephone"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <click selector="{{CheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <seeInCurrentUrl url="{{CheckoutPage.url}}/#payment" stepKey="assertCheckoutPaymentUrl"/> + + </test> +</tests> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html index 086cca814bec1..dcd726076d900 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html @@ -16,8 +16,8 @@ <!--/ko--> <!-- ko if: (isCustomerLoggedIn && customerHasAddresses) --> <div class="choice field"> - <input type="checkbox" class="checkbox" id="billing-save-in-address-book" data-bind="checked: saveInAddressBook" /> - <label class="label" for="billing-save-in-address-book"> + <input type="checkbox" class="checkbox" data-bind="checked: saveInAddressBook, attr: {id: 'billing-save-in-address-book-' + getCode($parent)}" /> + <label class="label" data-bind="attr: {for: 'billing-save-in-address-book-' + getCode($parent)}" > <span data-bind="i18n: 'Save in address book'"></span> </label> </div> diff --git a/app/code/Magento/Config/Test/Mftf/Page/AdminSalesConfigPage.xml b/app/code/Magento/Config/Test/Mftf/Page/AdminSalesConfigPage.xml new file mode 100644 index 0000000000000..1a99ff6533dbb --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Page/AdminSalesConfigPage.xml @@ -0,0 +1,12 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminSalesConfigPage" url="admin/system_config/edit/section/sales/{{var1}}" area="admin" parameterized="true" module="Magento_Config"> + <section name="AdminSalesConfigSection"/> + </page> +</pages> diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml new file mode 100644 index 0000000000000..4897e8415c1b8 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminSalesConfigSection.xml @@ -0,0 +1,13 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminSalesConfigSection"> + <element name="enableMAPUseSystemValue" type="checkbox" selector="#sales_msrp_enabled_inherit"/> + <element name="enableMAPSelect" type="select" selector="#sales_msrp_enabled"/> + </section> +</sections> \ No newline at end of file diff --git a/app/code/Magento/Cookie/view/frontend/web/js/notices.js b/app/code/Magento/Cookie/view/frontend/web/js/notices.js index 253950747ce14..f1f3754ea54b1 100644 --- a/app/code/Magento/Cookie/view/frontend/web/js/notices.js +++ b/app/code/Magento/Cookie/view/frontend/web/js/notices.js @@ -29,7 +29,7 @@ define([ }); if ($.mage.cookies.get(this.options.cookieName)) { - window.location.reload(); + this.element.hide(); } else { window.location.href = this.options.noCookiesUrl; } diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index a1f0277ec40ec..d26ecac28113e 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -85,6 +85,12 @@ </entity> <!--If required other field can be added to UK_Address entity, dont modify any existing data--> <entity name="UK_Address" type="address"> + <array key="street"> + <item>7700 xyz street</item> + <item>113</item> + </array> + <data key="city">London</data> <data key="country_id">GB</data> + <data key="telephone">512-345-6789</data> </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml b/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml index 747f2d59745a1..99741a357109e 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml @@ -20,11 +20,11 @@ <entity name="RegionCA" type="region"> <data key="region">California</data> <data key="region_code">CA</data> - <data key="region_id">2</data> + <data key="region_id">12</data> </entity> <entity name="RegionNY" type="region"> <data key="region">New York</data> <data key="region_code">NY</data> - <data key="region_id">3</data> + <data key="region_id">43</data> </entity> </entities> diff --git a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js index be2e0aedfe4bb..89d9b320c049d 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js +++ b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js @@ -31,7 +31,7 @@ define([ this.options.cache.label = $(this.options.passwordStrengthMeterLabelSelector, this.element); // We need to look outside the module for backward compatibility, since someone can already use the module. - // @todo Narrow this selector in 2.3 so it doesn't accidentally finds the the email field from the + // @todo Narrow this selector in 2.3 so it doesn't accidentally finds the email field from the // newsletter email field or any other "email" field. this.options.cache.email = $(this.options.formSelector).find(this.options.emailSelector); this._bind(); diff --git a/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php b/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php index b6ec06d48a487..118535c36560b 100644 --- a/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php @@ -17,7 +17,7 @@ class Elasticsearch implements ClientInterface /** * Elasticsearch Client instance * - * @var \Elasticsearch\Client + * @var \Elasticsearch\Client[] */ protected $client; @@ -53,10 +53,19 @@ public function __construct( $config = $this->buildConfig($options); $elasticsearchClient = \Elasticsearch\ClientBuilder::fromConfig($config, true); } - $this->client = $elasticsearchClient; + $this->client[getmypid()] = $elasticsearchClient; $this->clientOptions = $options; } + private function getClient() + { + $pid = getmypid(); + if (!isset($this->client[$pid])) { + $config = $this->buildConfig($this->clientOptions); + $this->client[$pid] = \Elasticsearch\ClientBuilder::fromConfig($config, true); + } + return $this->client[$pid]; + } /** * Ping the Elasticsearch client * @@ -65,7 +74,7 @@ public function __construct( public function ping() { if ($this->pingResult === null) { - $this->pingResult = $this->client->ping(['client' => ['timeout' => $this->clientOptions['timeout']]]); + $this->pingResult = $this->getClient()->ping(['client' => ['timeout' => $this->clientOptions['timeout']]]); } return $this->pingResult; } @@ -110,7 +119,7 @@ private function buildConfig($options = []) */ public function bulkQuery($query) { - $this->client->bulk($query); + $this->getClient()->bulk($query); } /** @@ -122,7 +131,7 @@ public function bulkQuery($query) */ public function createIndex($index, $settings) { - $this->client->indices()->create([ + $this->getClient()->indices()->create([ 'index' => $index, 'body' => $settings, ]); @@ -136,7 +145,7 @@ public function createIndex($index, $settings) */ public function deleteIndex($index) { - $this->client->indices()->delete(['index' => $index]); + $this->getClient()->indices()->delete(['index' => $index]); } /** @@ -147,7 +156,7 @@ public function deleteIndex($index) */ public function isEmptyIndex($index) { - $stats = $this->client->indices()->stats(['index' => $index, 'metric' => 'docs']); + $stats = $this->getClient()->indices()->stats(['index' => $index, 'metric' => 'docs']); if ($stats['indices'][$index]['primaries']['docs']['count'] == 0) { return true; } @@ -172,7 +181,7 @@ public function updateAlias($alias, $newIndex, $oldIndex = '') $params['body']['actions'][] = ['add' => ['alias' => $alias, 'index' => $newIndex]]; } - $this->client->indices()->updateAliases($params); + $this->getClient()->indices()->updateAliases($params); } /** @@ -183,7 +192,7 @@ public function updateAlias($alias, $newIndex, $oldIndex = '') */ public function indexExists($index) { - return $this->client->indices()->exists(['index' => $index]); + return $this->getClient()->indices()->exists(['index' => $index]); } /** @@ -198,7 +207,7 @@ public function existsAlias($alias, $index = '') if ($index) { $params['index'] = $index; } - return $this->client->indices()->existsAlias($params); + return $this->getClient()->indices()->existsAlias($params); } /** @@ -208,7 +217,7 @@ public function existsAlias($alias, $index = '') */ public function getAlias($alias) { - return $this->client->indices()->getAlias(['name' => $alias]); + return $this->getClient()->indices()->getAlias(['name' => $alias]); } /** @@ -267,7 +276,7 @@ public function addFieldsMapping(array $fields, $index, $entityType) foreach ($fields as $field => $fieldInfo) { $params['body'][$entityType]['properties'][$field] = $fieldInfo; } - $this->client->indices()->putMapping($params); + $this->getClient()->indices()->putMapping($params); } /** @@ -279,7 +288,7 @@ public function addFieldsMapping(array $fields, $index, $entityType) */ public function deleteMapping($index, $entityType) { - $this->client->indices()->deleteMapping([ + $this->getClient()->indices()->deleteMapping([ 'index' => $index, 'type' => $entityType, ]); @@ -293,8 +302,7 @@ public function deleteMapping($index, $entityType) */ public function query($query) { - $params = array_merge($query, ['client' => ['timeout' => $this->clientOptions['timeout']]]); - return $this->client->search($params); + return $this->getClient()->search($query); } /** @@ -305,6 +313,6 @@ public function query($query) */ public function suggest($query) { - return $this->client->suggest($query); + return $this->getClient()->suggest($query); } } diff --git a/app/code/Magento/Indexer/Model/ProcessManager.php b/app/code/Magento/Indexer/Model/ProcessManager.php new file mode 100644 index 0000000000000..04cd713fffb11 --- /dev/null +++ b/app/code/Magento/Indexer/Model/ProcessManager.php @@ -0,0 +1,156 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Indexer\Model; + +/** + * Provide functionality for executing user functions in multi-thread mode. + */ +class ProcessManager +{ + /** + * Threads count environment variable name + */ + const THREADS_COUNT = 'MAGE_INDEXER_THREADS_COUNT'; + + /** @var bool */ + private $failInChildProcess = false; + + /** @var \Magento\Framework\App\ResourceConnection */ + private $resource; + + /** @var \Magento\Framework\Registry */ + private $registry; + + /** @var int|null */ + private $threadsCount; + + /** + * @param \Magento\Framework\App\ResourceConnection $resource + * @param \Magento\Framework\Registry $registry + * @param int|null $threadsCount + */ + public function __construct( + \Magento\Framework\App\ResourceConnection $resource, + \Magento\Framework\Registry $registry = null, + int $threadsCount = null + ) { + $this->resource = $resource; + if (null === $registry) { + $registry = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\Registry::class + ); + } + $this->registry = $registry; + $this->threadsCount = (int)$threadsCount; + } + + /** + * Execute user functions + * + * @param \Traversable $userFunctions + */ + public function execute($userFunctions) + { + if ($this->threadsCount > 1 && $this->isCanBeParalleled() && !$this->isSetupMode() && PHP_SAPI == 'cli') { + $this->multiThreadsExecute($userFunctions); + } else { + $this->simpleThreadExecute($userFunctions); + } + } + + /** + * Execute user functions in singleThreads mode + * + * @param \Traversable $userFunctions + */ + private function simpleThreadExecute($userFunctions) + { + foreach ($userFunctions as $userFunction) { + call_user_func($userFunction); + } + } + + /** + * Execute user functions in multiThreads mode + * + * @param \Traversable $userFunctions + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + private function multiThreadsExecute($userFunctions) + { + $this->resource->closeConnection(null); + $threadNumber = 0; + foreach ($userFunctions as $userFunction) { + $pid = pcntl_fork(); + if ($pid == -1) { + throw new \RuntimeException('Unable to fork a new process'); + } elseif ($pid) { + $this->executeParentProcess($threadNumber); + } else { + $this->startChildProcess($userFunction); + } + } + while (pcntl_waitpid(0, $status) != -1) { + //Waiting for the completion of child processes + } + + if ($this->failInChildProcess) { + throw new \RuntimeException('Fail in child process'); + } + } + + /** + * Is process can be paralleled + * + * @return bool + */ + private function isCanBeParalleled(): bool + { + return function_exists('pcntl_fork'); + } + + /** + * Is setup mode + * + * @return bool + */ + private function isSetupMode(): bool + { + return $this->registry->registry('setup-mode-enabled') ?: false; + } + + /** + * Start child process + * + * @param callable $userFunction + * @SuppressWarnings(PHPMD.ExitExpression) + */ + private function startChildProcess(callable $userFunction) + { + $status = call_user_func($userFunction); + $status = is_integer($status) ? $status : 0; + exit($status); + } + + /** + * Execute parent process + * + * @param int $threadNumber + */ + private function executeParentProcess(int &$threadNumber) + { + $threadNumber++; + if ($threadNumber >= $this->threadsCount) { + pcntl_wait($status); + if (pcntl_wexitstatus($status) !== 0) { + $this->failInChildProcess = true; + } + $threadNumber--; + } + } +} diff --git a/app/code/Magento/Indexer/etc/di.xml b/app/code/Magento/Indexer/etc/di.xml index 610f08fac3a05..6abaaf625e108 100644 --- a/app/code/Magento/Indexer/etc/di.xml +++ b/app/code/Magento/Indexer/etc/di.xml @@ -42,7 +42,11 @@ <plugin name="page-cache-indexer-reindex-clean-cache" type="Magento\Indexer\Model\Processor\CleanCache" sortOrder="10"/> </type> - + <type name="\Magento\Indexer\Model\ProcessManager"> + <arguments> + <argument name="threadsCount" xsi:type="init_parameter">Magento\Indexer\Model\ProcessManager::THREADS_COUNT</argument> + </arguments> + </type> <type name="Magento\Framework\Console\CommandListInterface"> <arguments> <argument name="commands" xsi:type="array"> diff --git a/app/code/Magento/Integration/view/adminhtml/web/js/integration.js b/app/code/Magento/Integration/view/adminhtml/web/js/integration.js index 0bd7df8c0fa10..6921f645a2330 100644 --- a/app/code/Magento/Integration/view/adminhtml/web/js/integration.js +++ b/app/code/Magento/Integration/view/adminhtml/web/js/integration.js @@ -200,7 +200,7 @@ define([ if (IdentityLogin.win.closed || IdentityLogin.win.location.href == IdentityLogin.successCallbackUrl //eslint-disable-line eqeqeq ) { - //Stop the the polling + //Stop the polling clearInterval(IdentityLogin.checker); $('body').trigger('processStart'); //Check for window closed diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php index 79db83e7a49b8..33c3706183368 100644 --- a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php +++ b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php @@ -216,7 +216,7 @@ public function getForm() } /** - * Return return template name for JS + * Return template name for JS * * @return string */ diff --git a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php index 0487d7e46eb26..2405eaa9d37a3 100644 --- a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php +++ b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php @@ -45,6 +45,11 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\VersionContro */ protected $_quoteConfig; + /** + * @var \Magento\Store\Model\StoreManagerInterface|null + */ + private $storeManager; + /** * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory * @param \Psr\Log\LoggerInterface $logger @@ -56,6 +61,7 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\VersionContro * @param \Magento\Quote\Model\Quote\Config $quoteConfig * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource + * @param \Magento\Store\Model\StoreManagerInterface|null $storeManager * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -68,7 +74,8 @@ public function __construct( \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory, \Magento\Quote\Model\Quote\Config $quoteConfig, \Magento\Framework\DB\Adapter\AdapterInterface $connection = null, - \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null + \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null, + \Magento\Store\Model\StoreManagerInterface $storeManager = null ) { parent::__construct( $entityFactory, @@ -82,6 +89,10 @@ public function __construct( $this->_itemOptionCollectionFactory = $itemOptionCollectionFactory; $this->_productCollectionFactory = $productCollectionFactory; $this->_quoteConfig = $quoteConfig; + + // Backward compatibility constructor parameters + $this->storeManager = $storeManager ?: + \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Store\Model\StoreManagerInterface::class); } /** @@ -101,7 +112,10 @@ protected function _construct() */ public function getStoreId() { - return (int)$this->_productCollectionFactory->create()->getStoreId(); + // Fallback to current storeId if no quote is provided + // (see https://github.com/magento/magento2/commit/9d3be732a88884a66d667b443b3dc1655ddd0721) + return $this->_quote === null ? + (int) $this->storeManager->getStore()->getId() : (int) $this->_quote->getStoreId(); } /** diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderGridActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderGridActionGroup.xml index 7dcb89fdc1628..df0f56dbf7866 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderGridActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderGridActionGroup.xml @@ -68,4 +68,10 @@ <selectOption selector="{{AdminDataGridHeaderSection.filterFieldSelect('status')}}" userInput="{{status}}" stepKey="fillOrderStatusFilter"/> <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFilters"/> </actionGroup> + + <actionGroup name="AdminOrdersGridClearFiltersActionGroup"> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToGridOrdersPage"/> + <waitForPageLoad stepKey="waitForPageToLoad"/> + <conditionalClick selector="{{AdminOrdersGridSection.clearFilters}}" dependentSelector="{{AdminOrdersGridSection.enabledFilters}}" visible="true" stepKey="clickOnButtonToRemoveFiltersIfPresent"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index aa744787b0fef..49aae467b7e09 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -17,6 +17,7 @@ <element name="filters" type="button" selector="button[data-action='grid-filter-expand']" timeout="30"/> <element name="idFilter" type="input" selector=".admin__data-grid-filters input[name='increment_id']"/> <element name="billToNameFilter" type="input" selector=".admin__data-grid-filters input[name='billing_name']"/> + <element name="enabledFilters" type="block" selector=".admin__data-grid-header .admin__data-grid-filters-current._show"/> <element name="clearFilters" type="button" selector=".admin__data-grid-header [data-action='grid-filter-reset']" timeout="30"/> <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml index 2ff3d7756fe36..4cb72972b4ce2 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml @@ -23,6 +23,7 @@ <requiredEntity createDataKey="createCategory"/> </createData> <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearOrderFilters"/> <actionGroup ref="SetTaxClassForShipping" stepKey="setShippingTaxClass"/> </before> <after> @@ -30,6 +31,7 @@ <actionGroup ref="DeleteCartPriceRuleByName" stepKey="deleteSalesRule"> <argument name="ruleName" value="{{ApiSalesRule.name}}"/> </actionGroup> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearOrderFilters"/> <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> <deleteData createDataKey="createCategory" stepKey="deleteProduct1"/> <deleteData createDataKey="createProduct" stepKey="deleteCategory1"/> @@ -42,19 +44,15 @@ <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{ApiSalesRule.name}}" stepKey="fillRuleName"/> <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="selectWebsite"/> <actionGroup ref="selectNotLoggedInCustomerGroup" stepKey="chooseNotLoggedInCustomerGroup"/> - <!--<selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="NOT LOGGED IN" stepKey="selectCustomerGroup"/>--> <!-- Open the Actions Tab in the Rules Edit page --> <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> <waitForElementVisible selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="waitForElementToBeVisible"/> <click selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="enableApplyDiscountToShiping"/> - <seeCheckboxIsChecked selector="{{AdminCartPriceRulesFormSection.applyDiscountToShipping}}" stepKey="DiscountIsAppliedToShiping"/> + <seeCheckboxIsChecked selector="{{AdminCartPriceRulesFormSection.applyDiscountToShipping}}" stepKey="discountIsAppliedToShiping"/> <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Fixed amount discount" stepKey="selectActionType"/> <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="10" stepKey="fillDiscountAmount"/> - <!--<scrollTo selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="scrollToShippingLabel"/>--> - <!--<click selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="enableApplyDiscountToShiping"/>--> - <!--<seeCheckboxIsChecked selector="{{AdminCartPriceRulesFormSection.applyDiscountToShipping}}" stepKey="DiscountIsAppliedToShiping"/>--> <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> @@ -132,6 +130,6 @@ <assertEquals expected='-$15.00' expectedType="string" actual="($grabRefundDiscountValue)" message="notExpectedDiscountOnRefundPage" stepKey="assertDiscountValue1"/> <grabTextFrom selector="{{AdminInvoiceTotalSection.grandTotal}}" stepKey="grabRefundGrandTotal"/> <assertEquals expected="($grabInvoiceGrandTotal)" actual="($grabRefundGrandTotal)" message="RefundGrandTotalMatchesWithInvoiceGrandTotal" stepKey="compareRefundGrandTotalAndInvoiceGrandTotal"/> - </test> + </test> </tests> diff --git a/app/code/Magento/StoreGraphQl/Model/Resolver/Store/StoreConfigDataProvider.php b/app/code/Magento/StoreGraphQl/Model/Resolver/Store/StoreConfigDataProvider.php new file mode 100644 index 0000000000000..0252d7898beee --- /dev/null +++ b/app/code/Magento/StoreGraphQl/Model/Resolver/Store/StoreConfigDataProvider.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\StoreGraphQl\Model\Resolver\Store; + +use Magento\Store\Api\Data\StoreConfigInterface; +use Magento\Store\Api\StoreConfigManagerInterface; +use Magento\Store\Api\StoreRepositoryInterface; +use Magento\Store\Api\StoreResolverInterface; + +/** + * StoreConfig field data provider, used for GraphQL request processing. + */ +class StoreConfigDataProvider +{ + /** + * @var StoreConfigManagerInterface + */ + private $storeConfigManager; + + /** + * @var StoreResolverInterface + */ + private $storeResolver; + + /** + * @var StoreRepositoryInterface + */ + private $storeRepository; + + /** + * @param StoreConfigManagerInterface $storeConfigManager + * @param StoreResolverInterface $storeResolver + * @param StoreRepositoryInterface $storeRepository + */ + public function __construct( + StoreConfigManagerInterface $storeConfigManager, + StoreResolverInterface $storeResolver, + StoreRepositoryInterface $storeRepository + ) { + $this->storeConfigManager = $storeConfigManager; + $this->storeResolver = $storeResolver; + $this->storeRepository = $storeRepository; + } + + /** + * Get store config for current store + * + * @return array + */ + public function getStoreConfig() : array + { + $storeId = $this->storeResolver->getCurrentStoreId(); + $store = $this->storeRepository->getById($storeId); + $storeConfig = current($this->storeConfigManager->getStoreConfigs([$store->getCode()])); + + return $this->hidrateStoreConfig($storeConfig); + } + + /** + * Transform StoreConfig object to in array format + * + * @param StoreConfigInterface $storeConfig + * @return array + */ + private function hidrateStoreConfig($storeConfig): array + { + /** @var StoreConfigInterface $storeConfig */ + $storeConfigData = [ + 'id' => $storeConfig->getId(), + 'code' => $storeConfig->getCode(), + 'website_id' => $storeConfig->getWebsiteId(), + 'locale' => $storeConfig->getLocale(), + 'base_currency_code' => $storeConfig->getBaseCurrencyCode(), + 'default_display_currency_code' => $storeConfig->getDefaultDisplayCurrencyCode(), + 'timezone' => $storeConfig->getTimezone(), + 'weight_unit' => $storeConfig->getWeightUnit(), + 'base_url' => $storeConfig->getBaseUrl(), + 'base_link_url' => $storeConfig->getBaseLinkUrl(), + 'base_static_url' => $storeConfig->getSecureBaseStaticUrl(), + 'base_media_url' => $storeConfig->getBaseMediaUrl(), + 'secure_base_url' => $storeConfig->getSecureBaseUrl(), + 'secure_base_link_url' => $storeConfig->getSecureBaseLinkUrl(), + 'secure_base_static_url' => $storeConfig->getSecureBaseStaticUrl(), + 'secure_base_media_url' => $storeConfig->getSecureBaseMediaUrl() + ]; + + return $storeConfigData; + } +} diff --git a/app/code/Magento/StoreGraphQl/Model/Resolver/StoreConfigResolver.php b/app/code/Magento/StoreGraphQl/Model/Resolver/StoreConfigResolver.php new file mode 100644 index 0000000000000..8e5bf0120b8b8 --- /dev/null +++ b/app/code/Magento/StoreGraphQl/Model/Resolver/StoreConfigResolver.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\StoreGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\Resolver\Value; +use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\StoreGraphQl\Model\Resolver\Store\StoreConfigDataProvider; + +/** + * StoreConfig page field resolver, used for GraphQL request processing. + */ +class StoreConfigResolver implements ResolverInterface +{ + /** + * @var StoreConfigDataProvider + */ + private $storeConfigDataProvider; + + /** + * @var ValueFactory + */ + private $valueFactory; + + /** + * @param StoreConfigDataProvider $storeConfigsDataProvider + * @param ValueFactory $valueFactory + */ + public function __construct( + StoreConfigDataProvider $storeConfigsDataProvider, + ValueFactory $valueFactory + ) { + $this->valueFactory = $valueFactory; + $this->storeConfigDataProvider = $storeConfigsDataProvider; + } + + /** + * {@inheritdoc} + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) : Value { + + $storeConfigData = $this->storeConfigDataProvider->getStoreConfig(); + + $result = function () use ($storeConfigData) { + return !empty($storeConfigData) ? $storeConfigData : []; + }; + + return $this->valueFactory->create($result); + } +} diff --git a/app/code/Magento/StoreGraphQl/composer.json b/app/code/Magento/StoreGraphQl/composer.json index 91f79b39c023a..d03d759babd22 100644 --- a/app/code/Magento/StoreGraphQl/composer.json +++ b/app/code/Magento/StoreGraphQl/composer.json @@ -4,7 +4,8 @@ "type": "magento2-module", "require": { "php": "~7.1.3||~7.2.0", - "magento/framework": "*" + "magento/framework": "*", + "magento/module-store": "*" }, "suggest": { "magento/module-graph-ql": "*", diff --git a/app/code/Magento/StoreGraphQl/etc/schema.graphqls b/app/code/Magento/StoreGraphQl/etc/schema.graphqls index 6eea6da8fd6fa..af79d0e3e28b7 100644 --- a/app/code/Magento/StoreGraphQl/etc/schema.graphqls +++ b/app/code/Magento/StoreGraphQl/etc/schema.graphqls @@ -1,5 +1,8 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. +type Query { + storeConfig : StoreConfig @resolver(class: "Magento\\StoreGraphQl\\Model\\Resolver\\StoreConfigResolver") @doc(description: "The store config query") +} type Website @doc(description: "The type contains information about a website") { id : Int @doc(description: "The ID number assigned to the website") @@ -9,3 +12,22 @@ type Website @doc(description: "The type contains information about a website") default_group_id : String @doc(description: "The default group id that the website has") is_default : Boolean @doc(description: "Specifies if this is the default website") } + +type StoreConfig @doc(description: "The type contains information about a store config") { + id : Int @doc(description: "The ID number assigned to the store") + code : String @doc(description: "A code assigned to the store to identify it") + website_id : Int @doc(description: "The ID number assigned to the website store belongs") + locale : String @doc(description: "Store locale") + base_currency_code : String @doc(description: "Base currency code") + default_display_currency_code : String @doc(description: "Default display currency code") + timezone : String @doc(description: "Timezone of the store") + weight_unit : String @doc(description: "The unit of weight") + base_url : String @doc(description: "Base URL for the store") + base_link_url : String @doc(description: "Base link URL for the store") + base_static_url : String @doc(description: "Base static URL for the store") + base_media_url : String @doc(description: "Base media URL for the store") + secure_base_url : String @doc(description: "Secure base URL for the store") + secure_base_link_url : String @doc(description: "Secure base link URL for the store") + secure_base_static_url : String @doc(description: "Secure base static URL for the store") + secure_base_media_url : String @doc(description: "Secure base media URL for the store") +} diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxConfigData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxConfigData.xml new file mode 100644 index 0000000000000..d7c88c1d282e2 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxConfigData.xml @@ -0,0 +1,60 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- Default Tax Destination Calculation --> + <entity name="CountryUS" type="country"> + <data key="value">US</data> + </entity> + <entity name="AllPostCode" type="postcode"> + <data key="value">*</data> + </entity> + <!-- Shopping Cart Display Settings --> + <entity name="IncludeTaxInOrderTotalCart" type="grandtotalCart"> + <data key="value">1</data> + </entity> + <entity name="DisplayFullTaxSummaryCart" type="full_summaryCart"> + <data key="value">1</data> + </entity> + <entity name="DisplayZeroTaxSubtotalCart" type="zero_taxCart"> + <data key="value">1</data> + </entity> + <entity name="Tax_Config_CA" type="tax_config_state"> + <!-- Default Tax Destination Calculation --> + <requiredEntity type="country">CountryUS</requiredEntity> + <requiredEntity type="region">Region_CA</requiredEntity> + <requiredEntity type="postcode">AllPostCode</requiredEntity> + <!-- Shopping Cart Display Settings --> + <requiredEntity type="grandtotalCart">IncludeTaxInOrderTotalCart</requiredEntity> + <requiredEntity type="full_summaryCart">DisplayFullTaxSummaryCart</requiredEntity> + <requiredEntity type="zero_taxCart">DisplayZeroTaxSubtotalCart</requiredEntity> + </entity> + + <entity name="Tax_Config_NY" type="tax_config_state"> + <!-- Default Tax Destination Calculation --> + <requiredEntity type="country">CountryUS</requiredEntity> + <requiredEntity type="region">Region_NY</requiredEntity> + <requiredEntity type="postcode">AllPostCode</requiredEntity> + <!-- Shopping Cart Display Settings --> + <requiredEntity type="grandtotalCart">IncludeTaxInOrderTotalCart</requiredEntity> + <requiredEntity type="full_summaryCart">DisplayFullTaxSummaryCart</requiredEntity> + <requiredEntity type="zero_taxCart">DisplayZeroTaxSubtotalCart</requiredEntity> + </entity> + <!-- Set default settings --> + <entity name="DefaultTaxConfig" type="tax_config_default"> + <requiredEntity type="taxTotalFlagZero">DefaultTotalFlagZero</requiredEntity> + <requiredEntity type="taxPostCodeEmpty">EmptyField</requiredEntity> + </entity> + <entity name="DefaultTotalFlagZero" type="taxTotalFlagZero"> + <data key="value">0</data> + </entity> + <entity name="EmptyField" type="taxPostCodeEmpty"> + <data key="value"/> + </entity> +</entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRegionData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRegionData.xml new file mode 100644 index 0000000000000..c27225a339831 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRegionData.xml @@ -0,0 +1,17 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="Region_NY" type="region"> + <data key="value">43</data> + </entity> + <entity name="Region_CA" type="region"> + <data key="value">12</data> + </entity> +</entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml new file mode 100644 index 0000000000000..16c891745426d --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml @@ -0,0 +1,26 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SimpleTaxRule" type="taxRule"> + <data key="code" unique="suffix">TaxRule</data> + <data key="position">0</data> + <data key="priority">0</data> + <array key="customer_tax_class_ids"> + <item>3</item> + </array> + <array key="product_tax_class_ids"> + <item>2</item> + </array> + <array key="tax_rate_ids"> + <item>1</item> + <item>2</item> + </array> + <data key="calculate_subtotal">true</data> + </entity> +</entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Metadata/tax_config-meta.xml b/app/code/Magento/Tax/Test/Mftf/Metadata/tax_config-meta.xml new file mode 100644 index 0000000000000..137c2e48c111e --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Metadata/tax_config-meta.xml @@ -0,0 +1,183 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateTaxConfigDefaultsTaxDestination" dataType="tax_config_state" type="create" auth="adminFormKey" url="/admin/system_config/save/section/tax/" method="POST"> + <object key="groups" dataType="tax_config_state"> + <object key="defaults" dataType="tax_config_state"> + <object key="fields" dataType="tax_config_state"> + <object key="country" dataType="country"> + <field key="value">string</field> + </object> + <object key="region" dataType="region"> + <field key="value">string</field> + </object> + <object key="postcode" dataType="postcode"> + <field key="value">string</field> + </object> + </object> + </object> + <object key="cart_display" dataType="tax_config_state"> + <object key="fields" dataType="tax_config_state"> + <object key="grandtotal" dataType="grandtotalCart"> + <field key="value">string</field> + </object> + <object key="full_summary" dataType="full_summaryCart"> + <field key="value">string</field> + </object> + <object key="zero_tax" dataType="zero_taxCart"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> + <operation name="TaxConfigDefaultsTaxDestination" dataType="tax_config_default" type="create" auth="adminFormKey" url="/admin/system_config/save/section/tax/" method="POST"> + <object key="groups" dataType="tax_config_default"> + <object key="calculation" dataType="tax_config_default"> + <object key="fields" dataType="tax_config_default"> + <object key="algorithm" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="based_on" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="price_includes_tax" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="shipping_includes_tax" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="apply_after_discount" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="discount_tax" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="apply_tax_on" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="cross_border_trade_enabled" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + </object> + <object key="defaults" dataType="tax_config_default"> + <object key="fields" dataType="tax_config_default"> + <object key="country" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="region" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="postcode" dataType="taxPostCodeEmpty"> + <field key="value">string</field> + </object> + </object> + </object> + <object key="cart_display" dataType="tax_config_default"> + <object key="fields" dataType="tax_config_default"> + <object key="price" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="subtotal" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="shipping" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="gift_wrapping" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + <object key="printed_card" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + <object key="grandtotal" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="full_summary" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="zero_tax" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + <object key="sales_display" dataType="tax_config_default"> + <object key="fields" dataType="tax_config_default"> + <object key="price" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="subtotal" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="shipping" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="gift_wrapping" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + <object key="printed_card" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + <object key="grandtotal" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="full_summary" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="zero_tax" dataType="tax_config_default"> + <object key="inherit" dataType="taxTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Tax/Test/Mftf/Metadata/tax_rule-meta.xml b/app/code/Magento/Tax/Test/Mftf/Metadata/tax_rule-meta.xml new file mode 100644 index 0000000000000..f9886303fd3a3 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Metadata/tax_rule-meta.xml @@ -0,0 +1,33 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateTaxRule" dataType="taxRule" type="create" auth="adminOauth" url="/V1/taxRules" method="POST"> + <contentType>application/json</contentType> + <object key="rule" dataType="taxRule"> + <field key="id">integer</field> + <field key="code" required="true">string</field> + <field key="priority">integer</field> + <field key="position">integer</field> + <array key="customer_tax_class_ids"> + <value>integer</value> + </array> + <array key="product_tax_class_ids"> + <value>integer</value> + </array> + <array key="tax_rate_ids"> + <value>integer</value> + </array> + <field key="calculate_subtotal">boolean</field> + <field key="extension_attributes">empty_extension_attribute</field> + </object> + </operation> + <operation name="DeleteTaxRule" dataType="taxRule" type="delete" auth="adminOauth" url="/V1/taxRules/{id}" method="DELETE"> + <contentType>application/json</contentType> + </operation> +</operations> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index ad68179119834..c54c525d8d7ed 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -11,14 +11,29 @@ <section name="AdminConfigureTaxSection"> <!-- on page /admin/admin/system_config/edit/section/tax/ --> <element name="taxClasses" type="block" selector="#tax_classes-head" timeout="30"/> - <element name="calculationSettings" type="block" selector="#tax_calculation-head:not(.open)" timeout="30"/> - + + <element name="taxCalculationSettings" type="block" selector="#tax_calculation-head" timeout="30"/> + <element name="taxCalculationSettingsOpened" type="block" selector="#tax_calculation-head.open" timeout="30"/> + <element name="taxCalculationAlgorithm" type="select" selector="#tax_calculation_algorithm"/> + <element name="taxCalculationAlgorithmDisabled" type="select" selector="#tax_calculation_algorithm[disabled='disabled']"/> + <element name="taxCalculationAlgorithmInherit" type="checkbox" selector="#tax_calculation_algorithm_inherit"/> + <element name="taxCalculationBased" type="select" selector="#tax_calculation_based_on"/> + <element name="taxCalculationBasedDisabled" type="select" selector="#tax_calculation_based_on[disabled='disabled']"/> + <element name="taxCalculationBasedInherit" type="checkbox" selector="#tax_calculation_based_on_inherit"/> + <element name="taxCalculationPrices" type="select" selector="#tax_calculation_price_includes_tax"/> + <element name="taxCalculationPricesDisabled" type="select" selector="#tax_calculation_price_includes_tax[disabled='disabled']"/> + <element name="taxCalculationPricesInherit" type="checkbox" selector="#tax_calculation_price_includes_tax_inherit"/> + <element name="defaultDestination" type="block" selector="#tax_defaults-head" timeout="30"/> <element name="systemValueDefaultState" type="checkbox" selector="#row_tax_defaults_region input[type='checkbox']"/> <element name="dropdownDefaultState" type="select" selector="#row_tax_defaults_region select"/> - <element name="defaultPostCode" type="input" selector="#tax_defaults_postcode"/> + <element name="defaultPostCode" type="checkbox" selector="#tax_defaults_postcode"/> - <element name="priceDisplaySettings" type="block" selector="#tax_display-head:not(.open)" timeout="30"/> + <element name="taxPriceDisplaySettings" type="block" selector="#tax_display-head" timeout="30"/> + <element name="taxPriceDisplaySettingsOpened" type="block" selector="#tax_display-head.open" timeout="30"/> + <element name="taxDisplayProductPrices" type="select" selector="#tax_display_type"/> + <element name="taxDisplayProductPricesDisabled" type="select" selector="#tax_display_type[disabled='disabled']"/> + <element name="taxDisplayProductPricesInherit" type="checkbox" selector="#tax_display_type_inherit"/> <element name="shoppingCartDisplay" type="block" selector="#tax_cart_display-head" timeout="30"/> <element name="systemValueIncludeTaxTotalCart" type="checkbox" selector="#row_tax_cart_display_grandtotal input[type='checkbox']"/> @@ -35,7 +50,5 @@ <element name="dropdownDisplayTaxSummarySales" type="checkbox" selector="#row_tax_sales_display_full_summary select"/> <element name="systemValueDisplayZeroTaxSales" type="checkbox" selector="#row_tax_sales_display_zero_tax input[type='checkbox']"/> <element name="dropdownDisplayZeroTaxSales" type="checkbox" selector="#row_tax_sales_display_zero_tax select"/> - - <element name="priceDisplaySettings" type="block" selector="#tax_weee-head" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Tax/Test/Mftf/Section/CheckoutCartSummarySection.xml new file mode 100644 index 0000000000000..b47e8b85e5231 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Section/CheckoutCartSummarySection.xml @@ -0,0 +1,16 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CheckoutCartSummarySection"> + <element name="taxAmount" type="text" selector="[data-th='Tax']>span"/> + <element name="taxSummary" type="text" selector=".totals-tax-summary"/> + <element name="rate" type="text" selector=" tr.totals-tax-details.shown th.mark"/> + </section> +</sections> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml new file mode 100644 index 0000000000000..fdd6d18dae9c4 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml @@ -0,0 +1,119 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontTaxInformationInShoppingCartForCustomerPhysicalQuoteTest"> + <annotations> + <features value="Tax information in shopping cart for Customer with default addresses (physical quote)"/> + <title value="Tax information are updating/recalculating on fly in shopping cart for Customer with default addresses (physical quote)"/> + <description value="Tax information are updating/recalculating on fly in shopping cart for Customer with default addresses (physical quote)"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-41932"/> + <group value="checkout"/> + <group value="tax"/> + </annotations> + <before> + <!-- Preconditions --> + <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> + <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> + <!-- Fixed Product Tax attribute is created and added to default attribute set --> + <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> + <requiredEntity createDataKey="createProductFPTAttribute"/> + </createData> + <!-- Tax configuration (Store>Configuration; Sales>Tax) With FPT Enable --> + <createData entity="Tax_Config_NY" stepKey="taxConfigurationNYWithFPTEnable"/> + <!-- Store>Configuration; Sales>Tax FPT Enable --> + <createData entity="WeeeConfigEnable" stepKey="enableFPT"/> + <!-- Simple product is created Price = 10; FPT United States/California/10,United States/New York/20 --> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <field key="price">10.00</field> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!-- Customer is created with default addresses: --> + <createData entity="Simple_US_Customer_CA" stepKey="createCustomer"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="AdminProductAddFPTValueActionGroup" stepKey="addFPTValue1"> + <argument name="FPTAttributeCode" value="$$createProductFPTAttribute.attribute_code$$"/> + <argument name="stateForFPT" value="California"/> + <argument name="valueForFPT" value="10"/> + </actionGroup> + <actionGroup ref="AdminProductAddFPTValueActionGroup" stepKey="addFPTValue2"> + <argument name="FPTAttributeCode" value="$$createProductFPTAttribute.attribute_code$$"/> + <argument name="stateForFPT" value="New York"/> + <argument name="valueForFPT" value="20"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetGridToDefaultKeywordSearch"/> + </before> + <after> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + <deleteData createDataKey="createProductFPTAttribute" stepKey="deleteProductFPTAttribute"/> + <createData entity="DefaultTaxConfig" stepKey="defaultTaxConfiguration"/> + <createData entity="WeeeConfigDisable" stepKey="disableFPT"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!-- Test Steps --> + <!-- Step 1: Go to Storefront as logged in Customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$createCustomer$$" /> + </actionGroup> + <!-- Step 2: Add simple product to shopping cart --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="amOnSimpleProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddSimpleProductToCart"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="productCount" value="1"/> + </actionGroup> + <!-- Step 3: Go to Shopping Cart --> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToShoppingCartFromMinicart"/> + <!-- Step 4: Open Estimate Shipping and Tax section --> + <conditionalClick selector="{{CheckoutCartSummarySection.estimateShippingAndTax}}" dependentSelector="{{CheckoutCartSummarySection.country}}" visible="false" stepKey="expandEstimateShippingandTax" /> + <see selector="{{CheckoutCartSummarySection.country}}" userInput="$$createCustomer.country_id$$" stepKey="checkCustomerCountry" /> + <see selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="$$createCustomer.state$$" stepKey="checkCustomerRegion" /> + <see selector="{{CheckoutCartSummarySection.postcode}}" userInput="$$createCustomer.postcode$$" stepKey="checkCustomerPostcode" /> + <see selector="{{CheckoutCartSummarySection.amountFPT}}" userInput="$10" stepKey="checkFPTAmountCA" /> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.83" stepKey="checkTaxAmountCA" /> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary"/> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-CA-*-Rate 1 (8.25%)" stepKey="checkRateCA" /> + <!-- Step 5: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="Switzerland" stepKey="selectSwitzerlandCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="Aargau" stepKey="selectAargauRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="1234" stepKey="inputPostCode"/> + <!-- Step 6: Select shipping rate again(it need for get new totals request - performance reason) --> + <click selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectflatRateShippingMethodShippingMethod"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxAmount}}" stepKey="scrollToTaxSummary2" /> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.00" stepKey="checkTaxAmount" /> + <dontSeeElement selector="{{CheckoutCartSummarySection.amountFPT}}" stepKey="checkFPTIsNotDisplayed" /> + <!-- Step 7: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="United States" stepKey="selectUnitedStatesCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="New York" stepKey="selectNewYorkRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="12345" stepKey="inputPostCode2"/> + <!-- Step 8: Select shipping rate again(it need for get new totals request - performance reason) --> + <click selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectflatRateShippingMethodShippingMethod2"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary3" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary3"/> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.84" stepKey="checkTaxAmountNY" /> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-NY-*-Rate 1 (8.375%)" stepKey="checkRateNY" /> + <see selector="{{CheckoutCartSummarySection.amountFPT}}" userInput="$20" stepKey="checkFPTAmountNY" /> + </test> +</tests> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml new file mode 100644 index 0000000000000..c27af9a6f63f5 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml @@ -0,0 +1,83 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontTaxInformationInShoppingCartForCustomerVirtualQuoteTest"> + <annotations> + <features value="Tax information in shopping cart for Customer with default addresses (virtual quote)"/> + <title value="Tax information are updating/recalculating on fly in shopping cart for Customer with default addresses (virtual quote)"/> + <description value="Tax information are updating/recalculating on fly in shopping cart for Customer with default addresses (virtual quote)"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-41933"/> + <group value="checkout"/> + <group value="tax"/> + </annotations> + <before> + <!-- Preconditions --> + <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> + <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> + <!-- Fixed Product Tax attribute is created and added to default attribute set --> + <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> + <requiredEntity createDataKey="createProductFPTAttribute"/> + </createData> + <!-- Tax configuration (Store>Configuration; Sales>Tax) --> + <createData entity="Tax_Config_CA" stepKey="taxConfigurationCA"/> + <!-- Virtual product is created: --> + <createData entity="VirtualProduct" stepKey="createVirtualProduct"> + <field key="price">40.00</field> + </createData> + <!-- Customer is created with default addresses: --> + <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> + </before> + <after> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + <deleteData createDataKey="createProductFPTAttribute" stepKey="deleteProductFPTAttribute"/> + <createData entity="DefaultTaxConfig" stepKey="defaultTaxConfiguration"/> + <deleteData createDataKey="createVirtualProduct" stepKey="deleteVirtualProduct"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + </after> + <!-- Test Steps --> + <!-- Step 1: Go to Storefront as logged in Customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$createCustomer$$" /> + </actionGroup> + <!-- Step 2: Add virtual product to shopping cart --> + <amOnPage url="{{StorefrontProductPage.url($$createVirtualProduct.name$$)}}" stepKey="amOnStorefrontVirtualProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddVirtualProductToCart"> + <argument name="product" value="$$createVirtualProduct$$"/> + <argument name="productCount" value="1"/> + </actionGroup> + <!-- Step 3: Go to Shopping Cart --> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToShoppingCartFromMinicart"/> + <!-- Step 4: Open Estimate Shipping and Tax section --> + <conditionalClick selector="{{CheckoutCartSummarySection.estimateShippingAndTax}}" dependentSelector="{{CheckoutCartSummarySection.country}}" visible="false" stepKey="expandEstimateShippingandTax" /> + <see selector="{{CheckoutCartSummarySection.country}}" userInput="$$createCustomer.country_id$$" stepKey="checkCustomerCountry" /> + <see selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="$$createCustomer.state$$" stepKey="checkCustomerRegion" /> + <see selector="{{CheckoutCartSummarySection.postcode}}" userInput="$$createCustomer.postcode$$" stepKey="checkCustomerPostcode" /> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="expandTaxSummary"/> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-NY-*-Rate 1 (8.375%)" stepKey="checkRateNY" /> + <!-- Step 5: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="Switzerland" stepKey="selectSwitzerlandCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="Aargau" stepKey="selectAargauRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="1234" stepKey="inputPostCode"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxAmount}}" stepKey="scrollToTaxSummary2" /> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.00" stepKey="checkTaxAmount" /> + <!-- Step 6: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="United States" stepKey="selectUnitedStatesCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="California" stepKey="selectCaliforniaRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="90230" stepKey="inputPostCode2"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary3" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary2"/> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$3.30" stepKey="checkTaxAmount2" /> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-CA-*-Rate 1 (8.25%)" stepKey="checkRateCA" /> + </test> +</tests> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml new file mode 100644 index 0000000000000..891e8f4e7968b --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml @@ -0,0 +1,114 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontTaxInformationInShoppingCartForGuestPhysicalQuoteTest"> + <annotations> + <features value="Tax information in shopping cart for Guest (physical quote)"/> + <title value="Tax information are updating/recalculating on fly in shopping cart for Guest (physical quote)"/> + <description value="Tax information are updating/recalculating on fly in shopping cart for Guest (physical quote)"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-41930"/> + <!--Skip because of issue MAGETWO-90966 on 4 step--> + <group value="skip"/> + <group value="checkout"/> + <group value="tax"/> + </annotations> + <before> + <!-- Preconditions --> + <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> + <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> + <!-- Fixed Product Tax attribute is created and added to default attribute set --> + <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> + <requiredEntity createDataKey="createProductFPTAttribute"/> + </createData> + <!-- Tax configuration (Store>Configuration; Sales>Tax) --> + <createData entity="Tax_Config_CA" stepKey="taxConfigurationForCA"/> + <!-- Store>Configuration; Sales>Tax FPT Enable --> + <createData entity="WeeeConfigEnable" stepKey="enableFPT"/> + <!-- Simple product is created Price = 10; FPT United States/California/10,United States/New York/20 --> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <field key="price">10.00</field> + <requiredEntity createDataKey="createCategory"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="AdminProductAddFPTValueActionGroup" stepKey="addFPTValue1"> + <argument name="FPTAttributeCode" value="$$createProductFPTAttribute.attribute_code$$"/> + <argument name="stateForFPT" value="California"/> + <argument name="valueForFPT" value="10"/> + </actionGroup> + <actionGroup ref="AdminProductAddFPTValueActionGroup" stepKey="addFPTValue2"> + <argument name="FPTAttributeCode" value="$$createProductFPTAttribute.attribute_code$$"/> + <argument name="stateForFPT" value="New York"/> + <argument name="valueForFPT" value="20"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetGridToDefaultKeywordSearch"/> + </before> + <after> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + <deleteData createDataKey="createProductFPTAttribute" stepKey="deleteProductFPTAttribute"/> + <createData entity="DefaultTaxConfig" stepKey="defaultTaxConfiguration"/> + <createData entity="WeeeConfigDisable" stepKey="disableFPT"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!-- Test Steps --> + <!-- Step 1: Go to Storefront as Guest --> + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="amOnStorefrontPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <!-- Step 2: Add simple product to shopping cart --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="amOnSimpleProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddSimpleProductToCart"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="productCount" value="1"/> + </actionGroup> + <!-- Step 3: Go to Shopping Cart --> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToShoppingCartFromMinicart"/> + <!-- Step 4: Open Estimate Shipping and Tax section --> + <conditionalClick selector="{{CheckoutCartSummarySection.estimateShippingAndTax}}" dependentSelector="{{CheckoutCartSummarySection.country}}" visible="false" stepKey="expandEstimateShippingandTax" /> + <see selector="{{CheckoutCartSummarySection.amountFPT}}" userInput="$10" stepKey="checkFPTAmountCA" /> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.83" stepKey="checkTaxAmountCA" /> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary"/> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-CA-*-Rate 1 (8.25%)" stepKey="checkRateCA" /> + <!-- Step 5: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="Switzerland" stepKey="selectSwitzerlandCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="Aargau" stepKey="selectAargauRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="1234" stepKey="inputPostCode"/> + <!-- Step 6: Select shipping rate again(it need for get new totals request - performance reason) --> + <click selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectflatRateShippingMethodShippingMethod"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxAmount}}" stepKey="scrollToTaxSummary2" /> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.00" stepKey="checkTaxAmount" /> + <dontSeeElement selector="{{CheckoutCartSummarySection.amountFPT}}" stepKey="checkFPTIsNotDisplayed" /> + <!-- Step 7: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="United States" stepKey="selectUnitedStatesCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="New York" stepKey="selectNewYorkRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="12345" stepKey="inputPostCode2"/> + <!-- Step 8: Select shipping rate again(it need for get new totals request - performance reason) --> + <click selector="{{CheckoutCartSummarySection.flatRateShippingMethod}}" stepKey="selectflatRateShippingMethodShippingMethod2"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary3" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary2"/> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.84" stepKey="checkTaxAmountNY" /> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-NY-*-Rate 1 (8.375%)" stepKey="checkRateNY" /> + <see selector="{{CheckoutCartSummarySection.amountFPT}}" userInput="$20" stepKey="checkFPTAmountNY" /> + </test> +</tests> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml new file mode 100644 index 0000000000000..9f33c1a8b155a --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml @@ -0,0 +1,78 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontTaxInformationInShoppingCartForGuestVirtualQuoteTest"> + <annotations> + <features value="Tax information in shopping cart for Guest (virtual quote)"/> + <title value="Tax information are updating/recalculating on fly in shopping cart for Guest (virtual quote)"/> + <description value="Tax information are updating/recalculating on fly in shopping cart for Guest (virtual quote)"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-41931"/> + <!--Skip because of issue MAGETWO-90966 on 4 step--> + <group value="skip"/> + <group value="checkout"/> + <group value="tax"/> + </annotations> + <before> + <!-- Preconditions --> + <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> + <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> + <!-- Fixed Product Tax attribute is created and added to default attribute set --> + <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> + <requiredEntity createDataKey="createProductFPTAttribute"/> + </createData> + <!-- Tax configuration (Store>Configuration; Sales>Tax) --> + <createData entity="Tax_Config_CA" stepKey="taxConfigurationCA"/> + <!-- Virtual product is created: Price = 10 --> + <createData entity="VirtualProduct" stepKey="createVirtualProduct"> + <field key="price">40.00</field> + </createData> + </before> + <after> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + <deleteData createDataKey="createProductFPTAttribute" stepKey="deleteProductFPTAttribute"/> + <createData entity="DefaultTaxConfig" stepKey="defaultTaxConfiguration"/> + <deleteData createDataKey="createVirtualProduct" stepKey="deleteVirtualProduct"/> + </after> + <!-- Test Steps --> + <!-- Step 1: Go to Storefront as Guest --> + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="amOnStorefrontPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <!-- Step 2: Add virtual product to shopping cart --> + <amOnPage url="{{StorefrontProductPage.url($$createVirtualProduct.name$$)}}" stepKey="amOnStorefrontVirtualProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddVirtualProductToCart"> + <argument name="product" value="$$createVirtualProduct$$"/> + <argument name="productCount" value="1"/> + </actionGroup> + <!-- Step 3: Go to Shopping Cart --> + <actionGroup ref="clickViewAndEditCartFromMiniCart" stepKey="goToShoppingCartFromMinicart"/> + <!-- Step 4: Open Estimate Shipping and Tax section --> + <conditionalClick selector="{{CheckoutCartSummarySection.estimateShippingAndTax}}" dependentSelector="{{CheckoutCartSummarySection.country}}" visible="false" stepKey="expandEstimateShippingandTax" /> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary" /> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$3.30" stepKey="checkTaxAmountCA" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary"/> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-CA-*-Rate 1 (8.25%)" stepKey="checkRateCA" /> + <!-- Step 5: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="Switzerland" stepKey="selectSwitzerlandCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="Aargau" stepKey="selectAargauRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="1234" stepKey="inputPostCode"/> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$0.00" stepKey="checkTaxAmount" /> + <!-- Step 6: Change Data --> + <selectOption selector="{{CheckoutCartSummarySection.country}}" userInput="United States" stepKey="selectUnitedStatesCountry"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="New York" stepKey="selectNewYorkRegion"/> + <fillField selector="{{CheckoutCartSummarySection.postcode}}" userInput="12345" stepKey="inputPostCode2"/> + <scrollTo selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="scrollToTaxSummary2" /> + <click selector="{{CheckoutCartSummarySection.taxSummary}}" stepKey="taxSummary2"/> + <see selector="{{CheckoutCartSummarySection.taxAmount}}" userInput="$3.35" stepKey="checkTaxAmountNY" /> + <see selector="{{CheckoutCartSummarySection.rate}}" userInput="US-NY-*-Rate 1 (8.375%)" stepKey="checkRateNY" /> + </test> +</tests> diff --git a/app/code/Magento/Theme/view/frontend/templates/html/bugreport.phtml b/app/code/Magento/Theme/view/frontend/templates/html/bugreport.phtml index 5d8203244256e..f147b7085945f 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/bugreport.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/bugreport.phtml @@ -7,7 +7,7 @@ <small class="bugs"> <span><?= /* @escapeNotVerified */ __('Help Us Keep Magento Healthy') ?></span> <a href="http://www.magentocommerce.com/bug-tracking" - target="_blank"> + target="_blank" title="<?= /* @escapeNotVerified */ __('Report All Bugs') ?>"> <?= /* @escapeNotVerified */ __('Report All Bugs') ?> </a> </small> diff --git a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml index 8c3663337cbbe..17f8d7c70f574 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml @@ -18,6 +18,7 @@ <a class="logo" href="<?= $block->getUrl('') ?>" title="<?= /* @escapeNotVerified */ $storeName ?>"> <?php endif ?> <img src="<?= /* @escapeNotVerified */ $block->getLogoSrc() ?>" + title="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" alt="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" <?= $block->getLogoWidth() ? 'width="' . $block->getLogoWidth() . '"' : '' ?> <?= $block->getLogoHeight() ? 'height="' . $block->getLogoHeight() . '"' : '' ?> diff --git a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/autosave/editor_plugin_src.js b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/autosave/editor_plugin_src.js index 31bcb419fb178..e215f078c4b02 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/autosave/editor_plugin_src.js +++ b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/autosave/editor_plugin_src.js @@ -20,7 +20,7 @@ * 1. localStorage - A new feature of HTML 5, localStorage can store megabytes of data per domain * on the client computer. Data stored in the localStorage area has no expiration date, so we must * manage expiring the data ourselves. localStorage is fully supported by IE8, and it is supposed - * to be working in Firefox 3 and Safari 3.2, but in reality is is flaky in those browsers. As + * to be working in Firefox 3 and Safari 3.2, but in reality is flaky in those browsers. As * HTML 5 gets wider support, the AutoSave plugin will use it automatically. In Windows Vista/7, * localStorage is stored in the following folder: * C:\Users\[username]\AppData\Local\Microsoft\Internet Explorer\DOMStore\[tempFolder] @@ -297,7 +297,7 @@ }, /** - * This method will store the current contents in the the storage engine. + * This method will store the current contents in the storage engine. * * @method storeDraft */ diff --git a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/paste/editor_plugin_src.js b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/paste/editor_plugin_src.js index cec4abf98727a..db89eccc4e7ef 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/paste/editor_plugin_src.js +++ b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/plugins/paste/editor_plugin_src.js @@ -207,7 +207,7 @@ sel.setRng(oldRng); sel.setContent(''); - // For some odd reason we need to detach the the mceInsertContent call from the paste event + // For some odd reason we need to detach the mceInsertContent call from the paste event // It's like IE has a reference to the parent element that you paste in and the selection gets messed up // when it tries to restore the selection setTimeout(function() { diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/region.js b/app/code/Magento/Ui/view/base/web/js/form/element/region.js index fec69bf8558b5..45d38b339b50b 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/region.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/region.js @@ -49,6 +49,10 @@ define([ if (option && !option['is_region_required']) { this.error(false); this.validation = _.omit(this.validation, 'required-entry'); + registry.get(this.customName, function (input) { + input.validation['required-entry'] = false; + input.required(false); + }); } else { this.validation['required-entry'] = true; } diff --git a/app/code/Magento/Ui/view/base/web/templates/block-loader.html b/app/code/Magento/Ui/view/base/web/templates/block-loader.html index 3d8b730a9e8c5..cb28b09e4da83 100644 --- a/app/code/Magento/Ui/view/base/web/templates/block-loader.html +++ b/app/code/Magento/Ui/view/base/web/templates/block-loader.html @@ -6,6 +6,6 @@ --> <div data-role="loader" class="loading-mask" style="position: absolute;"> <div class="loader"> - <img src="<%= loaderImageHref %>" alt="Loading..." style="position: absolute;"> + <img src="<%= loaderImageHref %>" alt="Loading..." title="Loading..." style="position: absolute;"> </div> </div> diff --git a/app/code/Magento/Weee/Test/Mftf/ActionGroup/AdminProductAddFPTValueActionGroup.xml b/app/code/Magento/Weee/Test/Mftf/ActionGroup/AdminProductAddFPTValueActionGroup.xml new file mode 100644 index 0000000000000..c41eb7c02a557 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/ActionGroup/AdminProductAddFPTValueActionGroup.xml @@ -0,0 +1,24 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Navigate to create product page from product grid page--> + <actionGroup name="AdminProductAddFPTValueActionGroup"> + <arguments> + <argument name="FPTAttributeCode"/> + <argument name="countryForFPT" defaultValue="US" type="string"/> + <argument name="stateForFPT" type="string"/> + <argument name="valueForFPT" type="string"/> + </arguments> + <click selector="{{AdminProductAddFPTValueSection.addFPT(FPTAttributeCode)}}" stepKey="clickAddFPTButton1"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <selectOption selector="{{AdminProductAddFPTValueSection.selectCountryForFPT(FPTAttributeCode)}}" userInput="{{countryForFPT}}" stepKey="selectcountryForFPT"/> + <selectOption selector="{{AdminProductAddFPTValueSection.selectStateForFPT(FPTAttributeCode)}}" userInput="{{stateForFPT}}" stepKey="selectstateForFPT"/> + <fillField selector="{{AdminProductAddFPTValueSection.setTaxValueForFPT(FPTAttributeCode)}}" userInput="{{valueForFPT}}" stepKey="setTaxvalueForFPT"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml b/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml new file mode 100644 index 0000000000000..e981dae483f32 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml @@ -0,0 +1,20 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="productFPTAttribute" type="ProductAttribute"> + <data key="attribute_code" unique="suffix">attribute</data> + <data key="is_unique">true</data> + <data key="frontend_input">weee</data> + <data key="is_used_in_grid">true</data> + <data key="is_visible_in_grid">true</data> + <data key="is_filterable_in_grid">true</data> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> + </entity> +</entities> diff --git a/app/code/Magento/Weee/Test/Mftf/Data/WeeeConfigData.xml b/app/code/Magento/Weee/Test/Mftf/Data/WeeeConfigData.xml new file mode 100644 index 0000000000000..120dd10eee359 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Data/WeeeConfigData.xml @@ -0,0 +1,25 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- Fixed Product Taxes Enable--> + <entity name="WeeeConfigEnable" type="weee_config"> + <requiredEntity type="enableFPT">EnableFPT</requiredEntity> + </entity> + <entity name="EnableFPT" type="enableFPT"> + <data key="value">1</data> + </entity> + <!-- Fixed Product Taxes Disable--> + <entity name="WeeeConfigDisable" type="weee_config_default"> + <requiredEntity type="disableFPT">DisableFPT</requiredEntity> + </entity> + <entity name="DisableFPT" type="disableFPT"> + <data key="value">0</data> + </entity> +</entities> diff --git a/app/code/Magento/Weee/Test/Mftf/Metadata/weee_config-meta.xml b/app/code/Magento/Weee/Test/Mftf/Metadata/weee_config-meta.xml new file mode 100644 index 0000000000000..2e2b71c30ef47 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Metadata/weee_config-meta.xml @@ -0,0 +1,34 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="WeeeConfigEnable" dataType="weee_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/tax/" method="POST"> + <object key="groups" dataType="weee_config"> + <object key="weee" dataType="weee_config"> + <object key="fields" dataType="weee_config"> + <object key="enable" dataType="enableFPT"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> + <operation name="WeeeConfigDefault" dataType="weee_config_default" type="create" auth="adminFormKey" url="/admin/system_config/save/section/tax/" method="POST"> + <object key="groups" dataType="weee_config_default"> + <object key="weee" dataType="weee_config_default"> + <object key="fields" dataType="weee_config_default"> + <object key="enable" dataType="weee_config_default"> + <object key="inherit" dataType="disableFPT"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Weee/Test/Mftf/Page/AdminProductEditPage.xml b/app/code/Magento/Weee/Test/Mftf/Page/AdminProductEditPage.xml new file mode 100644 index 0000000000000..fa3663ee719e1 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Page/AdminProductEditPage.xml @@ -0,0 +1,14 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminProductEditPage" url="catalog/product/edit/id/{{product_id}}/" area="admin" module="Magento_Catalog"> + <section name="AdminProductAddFPTValueSection"/> + </page> +</pages> diff --git a/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml b/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml new file mode 100644 index 0000000000000..40a9a97f31425 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml @@ -0,0 +1,17 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminProductAddFPTValueSection"> + <element name="addFPT" type="button" selector="[data-index='{{FPTAttributeCode}}'] [data-action='add_new_row']" parameterized="true"/> + <element name="selectCountryForFPT" type="select" selector="(//select[contains(@name, 'product[{{FPTAttributeCode}}]') and contains(@name, '[country]')])[last()]" parameterized="true"/> + <element name="selectStateForFPT" type="select" selector="(//select[contains(@name, 'product[{{FPTAttributeCode}}]') and contains(@name, '[state]')])[last()]" parameterized="true"/> + <element name="setTaxValueForFPT" type="text" selector="(//input[contains(@name, 'product[{{FPTAttributeCode}}]') and contains(@name, '[value]')])[last()]" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Weee/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Weee/Test/Mftf/Section/CheckoutCartSummarySection.xml new file mode 100644 index 0000000000000..9b6541b93541d --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Section/CheckoutCartSummarySection.xml @@ -0,0 +1,14 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CheckoutCartSummarySection"> + <element name="amountFPT" type="text" selector=".totals td[data-th='FPT'] .price"/> + </section> +</sections> diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less index 6937855492263..7c71913ed8db3 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less @@ -14,7 +14,7 @@ display: inline-block; vertical-align: top; width: 100%; - background-color: #fff; + background-color: @color-white; border: 1px solid #ada89e; border-radius: 2px; @@ -72,7 +72,7 @@ top: 100%; margin: 1px -1px 0 -1px; border: 1px solid #cac2b5; - background: #fff; + background: @color-white; box-shadow: 0 2px 4px rgba(0, 0, 0, .2); z-index: 990; @@ -229,7 +229,7 @@ > input.ui-autocomplete-loading, > input.mage-suggest-state-loading { - background: #fff url("@{baseDir}mui/images/ajax-loader-small.gif") no-repeat 190px 50%; + background: @color-white url("@{baseDir}mui/images/ajax-loader-small.gif") no-repeat 190px 50%; } } diff --git a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less index eefbc11201d9c..2074106e719db 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less @@ -53,7 +53,7 @@ } .attribute-change-checkbox { - background: #fff; + background: @color-white; display: block; margin-top: 5px; diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less index 865ece970465d..73e1bcf4a7d58 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less @@ -16,7 +16,7 @@ ); .action.toggle { - background: #fff; + background: @color-white; border-radius: 0 1px 1px 0; border: 1px solid #ada89e; height: 33px; @@ -58,7 +58,7 @@ .action.toggle { padding: 0 3px; border: 1px solid #b7b2a7; - background: #fff; + background: @color-white; border-radius: 0 1px 1px 0; border-left: none; height: 50px; @@ -121,7 +121,7 @@ width: auto; .addafter { - background: #fff; + background: @color-white; border-width: 1px 0 1px 1px; direction: ltr; height: 33px; diff --git a/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less index 0eba6b0d361f8..3a7b6d30c914d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less @@ -299,7 +299,7 @@ .invitee_information .data-table tbody tr th, .inviter_information .data-table tbody tr td, .inviter_information .data-table tbody tr th { - background-color: #fff; + background-color: @color-white; border: 0; color: #666; padding: 9px 10px 10px; diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less index 17910d7c8e5b4..11e0fcc7c8b84 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less @@ -78,7 +78,7 @@ &.ui-state-active { z-index: 2; - background: #FFF; + background: @color-white; padding: 1px (@spacing-m - 1px); border: 2px solid #eb5202; margin: -1px; diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less index b66fed0c0a09a..487457372582a 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less @@ -525,7 +525,7 @@ right: 0; top: 100%; border: 1px solid #cac2b5; - background: #fff; + background: @color-white; box-shadow: 0 1px 1px rgba(0, 0, 0, .2); z-index: 990; } @@ -786,7 +786,7 @@ border-radius: 1px; padding: 4px; color: #303030; - background-color: #fff; + background-color: @color-white; font-weight: 500; font-size: 14px; height: 33px; @@ -860,7 +860,7 @@ input[type="radio"], input[type="checkbox"] { .lib-css(appearance, none, 1); - background: #fff; + background: @color-white; border-radius: 2px; border: 1px solid #adadad; cursor: pointer; @@ -945,7 +945,7 @@ } select[disabled] option[selected] { - color: #fff; + color: @color-white; background: #aaa; } @@ -1157,7 +1157,7 @@ .fieldset-wrapper, .fieldset { - background: #fff; + background: @color-white; border: 0; margin: 0; padding: 5px 0 38px; @@ -1574,7 +1574,7 @@ .multiselect-alt .item { position: relative; - border-top: 1px solid #fff; + border-top: 1px solid @color-white; cursor: pointer; } @@ -1651,7 +1651,7 @@ ~ .addafter strong { display: inline-block; - background: #fff; + background: @color-white; line-height: 24px; margin: 0 3px 0 0; padding-left: 4px; @@ -2041,7 +2041,7 @@ &:before { position: absolute; content: ""; - background-color: #fff; + background-color: @color-white; right: 0; top: 0; bottom: 0; @@ -2298,7 +2298,7 @@ // -------------------------------------- .preview-window { - background: #fff; + background: @color-white; } .preview-window .toolbar { @@ -2458,7 +2458,7 @@ } .attribute-popup .page-actions.fixed .page-actions-inner { - background: #fff; + background: @color-white; padding: 0; min-width: 100%; max-width: 100%; @@ -2757,7 +2757,7 @@ border: 1px solid #c9c2b8; border-width: 0 0 1px; padding: 6px 10px 7px; - background: #fff; + background: @color-white; .style2(); span { @@ -2769,7 +2769,7 @@ td { border: none; padding: 6px 10px 7px; - background: #fff; + background: @color-white; } tr:last-child td { @@ -2858,7 +2858,7 @@ .table-fieldset-alt tbody tr:nth-child(odd) td, .table-fieldset-alt tbody tr:nth-child(odd):hover td { - background: #fff; + background: @color-white; } // @@ -2918,7 +2918,7 @@ } .order-details-existing-customer { - background: #fff; + background: @color-white; padding-left: 0; position: relative; width: 77.9%; @@ -3035,7 +3035,7 @@ } .gift-options-tooltip { - background: #fff; + background: @color-white; border-radius: 5px; padding: 10px; box-shadow: 0 0 3px rgba(0, 0, 0, .3); @@ -3194,7 +3194,7 @@ left: 0; margin: 0 8px; padding: 10px; - background: #fff; + background: @color-white; } } @@ -3386,7 +3386,7 @@ .rma-popup, .cms-popup { - background: #fff; + background: @color-white; box-shadow: 0 3px 6px rgba(0, 0, 0, .4); cursor: default; position: fixed; @@ -3410,7 +3410,7 @@ } .rma-popup .content { - background: #fff; + background: @color-white; border-bottom: 1px solid #ccc; max-height: 400px; overflow: auto; @@ -3467,7 +3467,7 @@ .grid .rma-popup .form-list tr, .grid tr.even .rma-popup .form-list tr, .grid tr.on-mouse .rma-popup .form-list tr { - background: #fff !important; + background: @color-white !important; } // @@ -3885,7 +3885,7 @@ .defaultSkin { table.mceLayout { td { - background: #fff; + background: @color-white; } } diff --git a/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less b/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less index c0aa5510c6e07..7565ee88714f6 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less +++ b/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less @@ -360,7 +360,7 @@ td.col-type { position: relative; border-bottom-right-radius: 0; box-shadow: none; - background: #fff; + background: @color-white; &:after { position: absolute; @@ -369,7 +369,7 @@ td.col-type { right: 0; height: 2px; margin-top: -1px; - background: #fff; + background: @color-white; content: ''; z-index: 2; } diff --git a/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less index 52f1beafa32e1..daed96db717c7 100644 --- a/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less @@ -36,9 +36,9 @@ @_icon-font-content: @icon-search, @_icon-font-size: 35px, @_icon-font-line-height: 33px, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @minicart-icons-color-hover, - @_icon-font-color-active: @minicart-icons-color-hover, + @_icon-font-color: @header-icons-color, + @_icon-font-color-hover: @header-icons-color-hover, + @_icon-font-color-active: @header-icons-color-hover, @_icon-font-text-hide: true ); display: inline-block; diff --git a/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less index 23acf9ee8b08d..f785dd74d900e 100644 --- a/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less @@ -37,9 +37,9 @@ @_icon-font-size: 22px, @_icon-font-line-height: 28px, @_icon-font-margin: 0 @indent__s 0 0, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @minicart-icons-color-hover, - @_icon-font-color-active: @minicart-icons-color-hover, + @_icon-font-color: @header-icons-color, + @_icon-font-color-hover: @header-icons-color-hover, + @_icon-font-color-active: @header-icons-color-hover, @_icon-font-text-hide: true ); display: inline-block; diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less index 83157281561c2..2c177571b9f5a 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less @@ -261,6 +261,7 @@ .copyright { .lib-css(background-color, @copyright__background-color); .lib-css(color, @color-white); + box-sizing: border-box; display: block; padding: @indent__s; text-align: center; @@ -417,6 +418,12 @@ } } } + .page-footer, + .copyright { + bottom: 0; + position: absolute; + width: 100%; + } } .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php index 4f68090657a10..c7697a99875be 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php @@ -8,6 +8,7 @@ namespace Magento\GraphQl\Catalog; use Magento\Catalog\Api\Data\CategoryInterface; +use Magento\Catalog\Model\ResourceModel\Category\Collection as CategoryCollection; use Magento\Framework\DataObject; use Magento\TestFramework\TestCase\GraphQlAbstract; use Magento\Catalog\Api\Data\ProductInterface; @@ -283,16 +284,13 @@ public function testCategoryProducts() */ public function testAnchorCategory() { - /** @var \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection */ - $categoryCollection = $this->objectManager->create( - \Magento\Catalog\Model\ResourceModel\Category\Collection::class - ); + /** @var CategoryCollection $categoryCollection */ + $categoryCollection = $this->objectManager->create(CategoryCollection::class); $categoryCollection->addFieldToFilter('name', 'Category 1'); + /** @var CategoryInterface $category */ $category = $categoryCollection->getFirstItem(); - /** @var \Magento\Framework\EntityManager\MetadataPool $entityManagerMetadataPool */ - $entityManagerMetadataPool = $this->objectManager->create(\Magento\Framework\EntityManager\MetadataPool::class); - $categoryLinkField = $entityManagerMetadataPool->getMetadata(CategoryInterface::class)->getLinkField(); - $categoryId = $category->getData($categoryLinkField); + $categoryId = $category->getId(); + $this->assertNotEmpty($categoryId, "Preconditions failed: category is not available."); $query = <<<QUERY diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Store/StoreConfigResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Store/StoreConfigResolverTest.php new file mode 100644 index 0000000000000..4657a1e763ae1 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Store/StoreConfigResolverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Store; + +use Magento\Store\Api\Data\StoreConfigInterface; +use Magento\Store\Api\StoreConfigManagerInterface; +use Magento\Store\Api\StoreRepositoryInterface; +use Magento\Store\Api\StoreResolverInterface; +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test the GraphQL endpoint's StoreConfigs query + */ +class StoreConfigResolverTest extends GraphQlAbstract +{ + + /** @var ObjectManager */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Store/_files/store.php + */ + public function testGetStoreConfig() + { + /** @var StoreConfigManagerInterface $storeConfigsManager */ + $storeConfigsManager = $this->objectManager->get(StoreConfigManagerInterface::class); + /** @var StoreResolverInterface $storeResolver */ + $storeResolver = $this->objectManager->get(StoreResolverInterface::class); + /** @var StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->get(StoreRepositoryInterface::class); + $storeId = $storeResolver->getCurrentStoreId(); + $store = $storeRepository->getById($storeId); + /** @var StoreConfigInterface $storeConfig */ + $storeConfig = current($storeConfigsManager->getStoreConfigs([$store->getCode()])); + $query + = <<<QUERY +{ + storeConfig{ + id, + code, + website_id, + locale, + base_currency_code, + default_display_currency_code, + timezone, + weight_unit, + base_url, + base_link_url, + base_static_url, + base_media_url, + secure_base_url, + secure_base_link_url, + secure_base_static_url, + secure_base_media_url + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayHasKey('storeConfig', $response); + $this->assertEquals($storeConfig->getId(), $response['storeConfig']['id']); + $this->assertEquals($storeConfig->getCode(), $response['storeConfig']['code']); + $this->assertEquals($storeConfig->getLocale(), $response['storeConfig']['locale']); + $this->assertEquals($storeConfig->getBaseCurrencyCode(), $response['storeConfig']['base_currency_code']); + $this->assertEquals( + $storeConfig->getDefaultDisplayCurrencyCode(), + $response['storeConfig']['default_display_currency_code'] + ); + $this->assertEquals($storeConfig->getTimezone(), $response['storeConfig']['timezone']); + $this->assertEquals($storeConfig->getWeightUnit(), $response['storeConfig']['weight_unit']); + $this->assertEquals($storeConfig->getBaseUrl(), $response['storeConfig']['base_url']); + $this->assertEquals($storeConfig->getBaseLinkUrl(), $response['storeConfig']['base_link_url']); + $this->assertEquals($storeConfig->getBaseStaticUrl(), $response['storeConfig']['base_static_url']); + $this->assertEquals($storeConfig->getBaseMediaUrl(), $response['storeConfig']['base_media_url']); + $this->assertEquals($storeConfig->getSecureBaseUrl(), $response['storeConfig']['secure_base_url']); + $this->assertEquals($storeConfig->getSecureBaseLinkUrl(), $response['storeConfig']['secure_base_link_url']); + $this->assertEquals( + $storeConfig->getSecureBaseStaticUrl(), + $response['storeConfig']['secure_base_static_url'] + ); + $this->assertEquals($storeConfig->getSecureBaseMediaUrl(), $response['storeConfig']['secure_base_media_url']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/ProductRuleTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/ProductRuleTest.php index 76d17527d567a..911c7aa30641e 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/ProductRuleTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/ProductRuleTest.php @@ -67,7 +67,7 @@ public function testReindexWithProductNotVisibleIndividually() $this->assertEquals( 7.5, $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $product->getId()), - "Catalog price rule doesn't apply to to product with visibility value \"Not Visibility Individually\"" + "Catalog price rule doesn't apply to product with visibility value \"Not Visibility Individually\"" ); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php index 3ed330ed98d6b..336b438661705 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php @@ -262,7 +262,7 @@ public function testGetCustomerAttributeMetadata() $this->assertEquals( $attributeMetadata, $attributeMetadata1, - 'Attribute metadata from the the same service became different after getAttributeCode was called' + 'Attribute metadata from the same service became different after getAttributeCode was called' ); // Verify the consistency of attribute metadata from two services // after getAttributeCode was called diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml index 18501ecfbbfbf..8e50fe1888104 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml @@ -9,17 +9,17 @@ <block class="Magento\Framework\View\Element\Text" name="block1"> <block class="Magento\Framework\View\Element\Text" name="block2" group="group1"> <arguments> - <argument xsi:type="string" name="text">blok2</argument> + <argument xsi:type="string" name="text">block2</argument> </arguments> </block> <block class="Magento\Framework\View\Element\Text" name="block3" group="group1" > <arguments> - <argument xsi:type="string" name="text">blok3</argument> + <argument xsi:type="string" name="text">block3</argument> </arguments> </block> <block class="Magento\Framework\View\Element\Text" name="block4"> <arguments> - <argument xsi:type="string" name="text">blok4</argument> + <argument xsi:type="string" name="text">block4</argument> </arguments> </block> </block> diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php index e0bd6f3523612..dd5d12c5b9be3 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php @@ -2192,7 +2192,7 @@ protected function setupMultiRuleQuote() } /** - * Create the base results for the the multi rules test + * Create the base results for the multi rules test * * @return array * @SuppressWarnings(PHPMD.ExcessiveMethodLength) diff --git a/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php b/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php index f41c235a6c0f8..e3cfdf532438c 100644 --- a/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php @@ -64,7 +64,7 @@ protected function validateNamespace(File $sourceFile, $stackPtr) 'Cannot use "%s" in namespace as it is reserved since PHP %s', $stackPtr, 'Namespace', - [$namespacePart, $this->reservedWords[$namespacePart]] + [$namespacePart, $this->reservedWords[strtolower($namespacePart)]] ); } $stackPtr++; diff --git a/lib/internal/Magento/Framework/Api/Uploader.php b/lib/internal/Magento/Framework/Api/Uploader.php index d3ae11100b9dc..5cea3a34569a9 100644 --- a/lib/internal/Magento/Framework/Api/Uploader.php +++ b/lib/internal/Magento/Framework/Api/Uploader.php @@ -19,7 +19,7 @@ public function __construct() } /** - * Explicitly set the the file attributes instead of setting it via constructor + * Explicitly set the file attributes instead of setting it via constructor * * @param array $fileAttributes * @return void diff --git a/lib/internal/Magento/Framework/App/ResourceConnection.php b/lib/internal/Magento/Framework/App/ResourceConnection.php index 5b9ae925bff27..148053fa44e08 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection.php @@ -104,9 +104,21 @@ public function getConnection($resourceName = self::DEFAULT_CONNECTION) */ public function closeConnection($resourceName = self::DEFAULT_CONNECTION) { - $processConnectionName = $this->getProcessConnectionName($this->config->getConnectionName($resourceName)); - if (isset($this->connections[$processConnectionName])) { - $this->connections[$processConnectionName] = null; + if ($resourceName === null) { + foreach ($this->connections as $processConnection) { + if ($processConnection !== null) { + $processConnection->closeConnection(); + } + } + $this->connections = []; + } else { + $processConnectionName = $this->getProcessConnectionName($this->config->getConnectionName($resourceName)); + if (isset($this->connections[$processConnectionName])) { + if ($this->connections[$processConnectionName] !== null) { + $this->connections[$processConnectionName]->closeConnection(); + } + $this->connections[$processConnectionName] = null; + } } } diff --git a/lib/web/MutationObserver.js b/lib/web/MutationObserver.js index 53424fbfa8d0c..4044aa465e745 100644 --- a/lib/web/MutationObserver.js +++ b/lib/web/MutationObserver.js @@ -324,7 +324,7 @@ if (lastRecord === newRecord) return lastRecord; - // Check if the the record we are adding represents the same record. If + // Check if the record we are adding represents the same record. If // so, we keep the one with the oldValue in it. if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue; diff --git a/lib/web/css/docs/source/_buttons.less b/lib/web/css/docs/source/_buttons.less index a071eed85ef9e..300991338fb71 100644 --- a/lib/web/css/docs/source/_buttons.less +++ b/lib/web/css/docs/source/_buttons.less @@ -524,10 +524,10 @@ button { } &.example-button-6 { .lib-button-s(); - color: #fff; + color: @color-white; &:hover, &.active { - color: #fff; + color: @color-white; } } } @@ -721,13 +721,13 @@ button { @_button-padding: @button__padding, @_button-gradient-color-start: #1979c3, @_button-gradient-color-end: #006bb4, - @_button-color: #fff, + @_button-color: @color-white, @_button-gradient-color-start-hover: #006bb4, @_button-gradient-color-end-hover: #1979c3, - @_button-color-hover: #fff, + @_button-color-hover: @color-white, @_button-gradient-color-start-active: #006bb4, @_button-gradient-color-end-active: #006bb4, - @_button-color-active: #fff, + @_button-color-active: @color-white, @_button-gradient: true, @_button-gradient-direction: vertical, @_button-border: @button-primary__border, diff --git a/lib/web/css/docs/source/_pages.less b/lib/web/css/docs/source/_pages.less index 0b94f84e54f47..6b01fa7549e92 100644 --- a/lib/web/css/docs/source/_pages.less +++ b/lib/web/css/docs/source/_pages.less @@ -852,22 +852,22 @@ .example-pages-3 { .lib-pager( @_pager-label-display: none, - @_pager-color: #fff, + @_pager-color: @color-white, @_pager-background: @link__color, - @_pager-color-visited: #fff, + @_pager-color-visited: @color-white, @_pager-background-visited: @link__visited__color, - @_pager-color-hover: #fff, + @_pager-color-hover: @color-white, @_pager-background-hover: @link__hover__color, - @_pager-color-active: #fff, + @_pager-color-active: @color-white, @_pager-background-active: @link__active__color, - @_pager-current-color: #fff, + @_pager-current-color: @color-white, @_pager-current-background: @link__visited__color, @_pager-action-background: @link__color, @_pager-action-background-visited: @link__visited__color, @_pager-action-background-hover: @link__hover__color, @_pager-action-background-active: @link__active__color, - @_pager-action-color: #fff, - @_pager-action-color-hover: #fff, - @_pager-action-color-active: #fff + @_pager-action-color: @color-white, + @_pager-action-color-hover: @color-white, + @_pager-action-color-active: @color-white ); } diff --git a/lib/web/css/docs/source/_tables.less b/lib/web/css/docs/source/_tables.less index 9d0df2350cee9..3f7f940187f50 100644 --- a/lib/web/css/docs/source/_tables.less +++ b/lib/web/css/docs/source/_tables.less @@ -677,7 +677,7 @@ .example-table-5 { .lib-table(); .lib-table-background-color( - @_table-background-color: #fff, + @_table-background-color: @color-white, @_table-head-background-color: #ccf, @_table-foot-background-color: #cff, @_table-td-background-color: #fcc, diff --git a/lib/web/mage/requirejs/static.js b/lib/web/mage/requirejs/static.js index 237aa0c6a8a63..898850cb2948b 100644 --- a/lib/web/mage/requirejs/static.js +++ b/lib/web/mage/requirejs/static.js @@ -13,7 +13,7 @@ define('buildTools', [ isEnabled: storage.getItem(storeName) === null, /** - * Removes base url from the the provided string + * Removes base url from the provided string * * @param {String} url - Url to be processed. * @param {Object} config - RequiereJs config object. diff --git a/lib/web/modernizr/modernizr.js b/lib/web/modernizr/modernizr.js index 0833cfb105cee..d7ddc86f63cae 100644 --- a/lib/web/modernizr/modernizr.js +++ b/lib/web/modernizr/modernizr.js @@ -1013,7 +1013,7 @@ window.Modernizr = (function( window, document, undefined ) { /** Name of the expando, to work with multiple documents or to re-shiv one document */ var expando = '_html5shiv'; - /** The id for the the documents expando */ + /** The id for the documents expando */ var expanID = 0; /** Cached data for each document */ diff --git a/setup/pub/angular/angular.js b/setup/pub/angular/angular.js index f53b5280f8647..e3a85e3679ac6 100644 --- a/setup/pub/angular/angular.js +++ b/setup/pub/angular/angular.js @@ -7770,7 +7770,7 @@ * caching. * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} * that should abort the request when resolved. - * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the + * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the * XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5 * for more information. * - **responseType** - `{string}` - see diff --git a/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php index 178102aa0b3b7..94337dd0742e3 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php @@ -11,8 +11,10 @@ use Magento\Framework\Filesystem\Driver\File; use Magento\Framework\Setup\BackupRollback; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\TableFactory; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Magento\Framework\App\ObjectManager; /** * Command prints list of available backup files @@ -33,16 +35,24 @@ class InfoBackupsListCommand extends Command */ private $directoryList; + /** + * @var TableFactory + */ + private $tableHelperFactory; + /** * @param DirectoryList $directoryList * @param File $file + * @param TableFactory $tableHelperFactory */ public function __construct( DirectoryList $directoryList, - File $file + File $file, + TableFactory $tableHelperFactory = null ) { $this->directoryList = $directoryList; $this->file = $file; + $this->tableHelperFactory = $tableHelperFactory ?: ObjectManager::getInstance()->create(TableFactory::class); parent::__construct(); } @@ -90,14 +100,14 @@ protected function execute(InputInterface $input, OutputInterface $output) return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } $output->writeln("<info>Showing backup files in $backupsDir.</info>"); - /** @var \Symfony\Component\Console\Helper\Table $table */ - $table = $this->getHelperSet()->get('table'); - $table->setHeaders(['Backup Filename', 'Backup Type']); + /** @var \Symfony\Component\Console\Helper\Table $tableHelper */ + $tableHelper = $this->tableHelperFactory->create(['output' => $output]); + $tableHelper->setHeaders(['Backup Filename', 'Backup Type']); asort($tempTable); foreach ($tempTable as $key => $value) { - $table->addRow([$key, $value]); + $tableHelper->addRow([$key, $value]); } - $table->render($output); + $tableHelper->render(); } else { $output->writeln('<info>No backup files found.</info>'); } diff --git a/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php index d673fc85c1ef1..91cfb5e7f6b5c 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php @@ -6,10 +6,12 @@ namespace Magento\Setup\Console\Command; +use Symfony\Component\Console\Helper\TableFactory; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Command\Command; use Magento\Framework\Setup\Lists; +use Magento\Framework\App\ObjectManager; /** * Command prints list of available currencies @@ -23,12 +25,19 @@ class InfoCurrencyListCommand extends Command */ private $lists; + /** + * @var TableFactory + */ + private $tableHelperFactory; + /** * @param Lists $lists + * @param TableFactory $tableHelperFactory */ - public function __construct(Lists $lists) + public function __construct(Lists $lists, TableFactory $tableHelperFactory = null) { $this->lists = $lists; + $this->tableHelperFactory = $tableHelperFactory ?: ObjectManager::getInstance()->create(TableFactory::class); parent::__construct(); } @@ -48,14 +57,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $table = $this->getHelperSet()->get('table'); - $table->setHeaders(['Currency', 'Code']); + $tableHelper = $this->tableHelperFactory->create(['output' => $output]); + $tableHelper->setHeaders(['Currency', 'Code']); foreach ($this->lists->getCurrencyList() as $key => $currency) { - $table->addRow([$currency, $key]); + $tableHelper->addRow([$currency, $key]); } - $table->render($output); + $tableHelper->render(); return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php index 88d1bdd5601d5..8950bd5edb2fa 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php @@ -6,8 +6,10 @@ namespace Magento\Setup\Console\Command; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Setup\Lists; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\TableFactory; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -23,12 +25,19 @@ class InfoLanguageListCommand extends Command */ private $lists; + /** + * @var TableFactory + */ + private $tableHelperFactory; + /** * @param Lists $lists + * @param TableFactory $tableHelperFactory */ - public function __construct(Lists $lists) + public function __construct(Lists $lists, TableFactory $tableHelperFactory = null) { $this->lists = $lists; + $this->tableHelperFactory = $tableHelperFactory ?: ObjectManager::getInstance()->create(TableFactory::class); parent::__construct(); } @@ -48,14 +57,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $table = $this->getHelperSet()->get('table'); - $table->setHeaders(['Language', 'Code']); + $tableHelper = $this->tableHelperFactory->create(['output' => $output]); + $tableHelper->setHeaders(['Language', 'Code']); foreach ($this->lists->getLocaleList() as $key => $locale) { - $table->addRow([$locale, $key]); + $tableHelper->addRow([$locale, $key]); } - $table->render($output); + $tableHelper->render(); return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php index 95b4cd27bbd3a..2ff1d228dfe24 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php @@ -10,6 +10,8 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Command\Command; use Magento\Framework\Setup\Lists; +use Symfony\Component\Console\Helper\TableFactory; +use Magento\Framework\App\ObjectManager; /** * Command prints list of available timezones @@ -23,12 +25,19 @@ class InfoTimezoneListCommand extends Command */ private $lists; + /** + * @var TableFactory + */ + private $tableHelperFactory; + /** * @param Lists $lists + * @param TableFactory $tableHelperFactory */ - public function __construct(Lists $lists) + public function __construct(Lists $lists, TableFactory $tableHelperFactory = null) { $this->lists = $lists; + $this->tableHelperFactory = $tableHelperFactory ?: ObjectManager::getInstance()->create(TableFactory::class); parent::__construct(); } @@ -48,14 +57,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $table = $this->getHelperSet()->get('table'); - $table->setHeaders(['Timezone', 'Code']); + $tableHelper = $this->tableHelperFactory->create(['output' => $output]); + $tableHelper->setHeaders(['Timezone', 'Code']); foreach ($this->lists->getTimezoneList() as $key => $timezone) { - $table->addRow([$timezone, $key]); + $tableHelper->addRow([$timezone, $key]); } - $table->render($output); + $tableHelper->render(); return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php index a7dc4dd1e6099..a1a62dc594683 100644 --- a/setup/src/Magento/Setup/Model/Installer.php +++ b/setup/src/Magento/Setup/Model/Installer.php @@ -815,6 +815,11 @@ public function declarativeInstallSchema(array $request) */ public function installSchema(array $request) { + /** @var \Magento\Framework\Registry $registry */ + $registry = $this->objectManagerProvider->get()->get(\Magento\Framework\Registry::class); + //For backward compatibility in install and upgrade scripts with enabled parallelization. + $registry->register('setup-mode-enabled', true); + $this->assertDbConfigExists(); $this->assertDbAccessible(); $setup = $this->setupFactory->create($this->context->getResources()); @@ -831,6 +836,8 @@ public function installSchema(array $request) $schemaListener->setResource('default'); $this->schemaPersistor->persist($schemaListener); } + + $registry->unregister('setup-mode-enabled'); } /** @@ -853,12 +860,19 @@ private function convertationOfOldScriptsIsAllowed(array $request) */ public function installDataFixtures(array $request = []) { + /** @var \Magento\Framework\Registry $registry */ + $registry = $this->objectManagerProvider->get()->get(\Magento\Framework\Registry::class); + //For backward compatibility in install and upgrade scripts with enabled parallelization. + $registry->register('setup-mode-enabled', true); + $this->assertDbConfigExists(); $this->assertDbAccessible(); $setup = $this->dataSetupFactory->create(); $this->checkFilePermissionsForDbUpgrade(); $this->log->log('Data install/update:'); $this->handleDBSchemaData($setup, 'data', $request); + + $registry->unregister('setup-mode-enabled'); } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoBackupsListCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoBackupsListCommandTest.php index ff4722ca0fd4a..1329324b74015 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoBackupsListCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoBackupsListCommandTest.php @@ -16,9 +16,9 @@ public function testExecute() $table = $this->createMock(\Symfony\Component\Console\Helper\Table::class); $table->expects($this->once())->method('setHeaders')->with(['Backup Filename', 'Backup Type']); $table->expects($this->once())->method('addRow')->with(['backupFile_media.tgz', 'media']); - /** @var \Symfony\Component\Console\Helper\HelperSet|\PHPUnit_Framework_MockObject_MockObject $helperSet */ - $helperSet = $this->createMock(\Symfony\Component\Console\Helper\HelperSet::class); - $helperSet->expects($this->once())->method('get')->with('table')->will($this->returnValue($table)); + /** @var \Symfony\Component\Console\Helper\TableFactory|\PHPUnit_Framework_MockObject_MockObject $helperSet */ + $tableFactoryMock = $this->createMock(\Symfony\Component\Console\Helper\TableFactory::class); + $tableFactoryMock->expects($this->once())->method('create')->will($this->returnValue($table)); /** @var \Magento\Framework\App\Filesystem\DirectoryList * |\PHPUnit_Framework_MockObject_MockObject $directoryList */ @@ -29,8 +29,7 @@ public function testExecute() $file->expects($this->once()) ->method('readDirectoryRecursively') ->will($this->returnValue(['backupFile_media.tgz'])); - $command = new InfoBackupsListCommand($directoryList, $file); - $command->setHelperSet($helperSet); + $command = new InfoBackupsListCommand($directoryList, $file, $tableFactoryMock); $commandTester = new CommandTester($command); $commandTester->execute([]); $expected = 'Showing backup files in '; diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoCurrencyListCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoCurrencyListCommandTest.php index e3e0a1de71727..caee4af9c7fc4 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoCurrencyListCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoCurrencyListCommandTest.php @@ -21,15 +21,14 @@ public function testExecute() $table->expects($this->once())->method('setHeaders')->with(['Currency', 'Code']); $table->expects($this->once())->method('addRow')->with(['Currency description', 'CUR']); - /** @var \Symfony\Component\Console\Helper\HelperSet|\PHPUnit_Framework_MockObject_MockObject $helperSet */ - $helperSet = $this->createMock(\Symfony\Component\Console\Helper\HelperSet::class); - $helperSet->expects($this->once())->method('get')->with('table')->will($this->returnValue($table)); + /** @var \Symfony\Component\Console\Helper\TableFactory|\PHPUnit_Framework_MockObject_MockObject $helperSet */ + $tableFactoryMock = $this->createMock(\Symfony\Component\Console\Helper\TableFactory::class); + $tableFactoryMock->expects($this->once())->method('create')->will($this->returnValue($table)); /** @var \Magento\Framework\Setup\Lists|\PHPUnit_Framework_MockObject_MockObject $list */ $list = $this->createMock(\Magento\Framework\Setup\Lists::class); $list->expects($this->once())->method('getCurrencyList')->will($this->returnValue($currencies)); - $command = new InfoCurrencyListCommand($list); - $command->setHelperSet($helperSet); + $command = new InfoCurrencyListCommand($list, $tableFactoryMock); $commandTester = new CommandTester($command); $commandTester->execute([]); } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoLanguageListCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoLanguageListCommandTest.php index f1622b59c4593..d9c899b178c37 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoLanguageListCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoLanguageListCommandTest.php @@ -21,15 +21,14 @@ public function testExecute() $table->expects($this->once())->method('setHeaders')->with(['Language', 'Code']); $table->expects($this->once())->method('addRow')->with(['Language description', 'LNG']); - /** @var \Symfony\Component\Console\Helper\HelperSet|\PHPUnit_Framework_MockObject_MockObject $helperSet */ - $helperSet = $this->createMock(\Symfony\Component\Console\Helper\HelperSet::class); - $helperSet->expects($this->once())->method('get')->with('table')->will($this->returnValue($table)); + /** @var \Symfony\Component\Console\Helper\TableFactory|\PHPUnit_Framework_MockObject_MockObject $helperSet */ + $tableFactoryMock = $this->createMock(\Symfony\Component\Console\Helper\TableFactory::class); + $tableFactoryMock->expects($this->once())->method('create')->will($this->returnValue($table)); /** @var \Magento\Framework\Setup\Lists|\PHPUnit_Framework_MockObject_MockObject $list */ $list = $this->createMock(\Magento\Framework\Setup\Lists::class); $list->expects($this->once())->method('getLocaleList')->will($this->returnValue($languages)); - $command = new InfoLanguageListCommand($list); - $command->setHelperSet($helperSet); + $command = new InfoLanguageListCommand($list, $tableFactoryMock); $commandTester = new CommandTester($command); $commandTester->execute([]); } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoTimezoneListCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoTimezoneListCommandTest.php index 860862f304971..80871ecf634ed 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoTimezoneListCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoTimezoneListCommandTest.php @@ -21,15 +21,14 @@ public function testExecute() $table->expects($this->once())->method('setHeaders')->with(['Timezone', 'Code']); $table->expects($this->once())->method('addRow')->with(['timezone description', 'timezone']); - /** @var \Symfony\Component\Console\Helper\HelperSet|\PHPUnit_Framework_MockObject_MockObject $helperSet */ - $helperSet = $this->createMock(\Symfony\Component\Console\Helper\HelperSet::class); - $helperSet->expects($this->once())->method('get')->with('table')->will($this->returnValue($table)); + /** @var \Symfony\Component\Console\Helper\TableFactory|\PHPUnit_Framework_MockObject_MockObject $helperSet */ + $tableFactoryMock = $this->createMock(\Symfony\Component\Console\Helper\TableFactory::class); + $tableFactoryMock->expects($this->once())->method('create')->will($this->returnValue($table)); /** @var \Magento\Framework\Setup\Lists|\PHPUnit_Framework_MockObject_MockObject $list */ $list = $this->createMock(\Magento\Framework\Setup\Lists::class); $list->expects($this->once())->method('getTimezoneList')->will($this->returnValue($timezones)); - $command = new InfoTimezoneListCommand($list); - $command->setHelperSet($helperSet); + $command = new InfoTimezoneListCommand($list, $tableFactoryMock); $commandTester = new CommandTester($command); $commandTester->execute([]); } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php index 413094a1e0115..882483ce7674a 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php @@ -267,6 +267,9 @@ private function createObject($connectionFactory = false, $objectManagerProvider ); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testInstall() { $request = [ @@ -316,6 +319,7 @@ public function testInstall() $appState->expects($this->once()) ->method('setAreaCode') ->with(\Magento\Framework\App\Area::AREA_GLOBAL); + $registry = $this->createMock(\Magento\Framework\Registry::class); $this->setupFactory->expects($this->atLeastOnce())->method('create')->with($resource)->willReturn($setup); $this->dataSetupFactory->expects($this->atLeastOnce())->method('create')->willReturn($dataSetup); $this->objectManager->expects($this->any()) @@ -346,7 +350,8 @@ public function testInstall() ->will($this->returnValueMap([ [\Magento\Framework\App\State::class, $appState], [\Magento\Framework\App\Cache\Manager::class, $cacheManager], - [\Magento\Setup\Model\DeclarationInstaller::class, $this->declarationInstallerMock] + [\Magento\Setup\Model\DeclarationInstaller::class, $this->declarationInstallerMock], + [\Magento\Framework\Registry::class, $registry] ])); $this->adminFactory->expects($this->once())->method('create')->willReturn( $this->createMock(\Magento\Setup\Model\AdminAccount::class)