diff --git a/app/code/Magento/AdminAnalytics/Test/Mftf/Test/AdminCheckAnalyticsTrackingTest.xml b/app/code/Magento/AdminAnalytics/Test/Mftf/Test/AdminCheckAnalyticsTrackingTest.xml new file mode 100644 index 0000000000000..4f0e9bb000a27 --- /dev/null +++ b/app/code/Magento/AdminAnalytics/Test/Mftf/Test/AdminCheckAnalyticsTrackingTest.xml @@ -0,0 +1,35 @@ + + + + + + + + + <description value="AdminAnalytics Check Tracking."/> + <severity value="MINOR"/> + <testCaseId value="MC-36869"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + <magentoCLI command="config:set admin/usage/enabled 1" stepKey="enableAdminUsageTracking"/> + <actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanInvalidatedCaches"> + <argument name="tags" value="config full_page"/> + </actionGroup> + <reloadPage stepKey="pageReload"/> + </before> + <after> + <magentoCLI command="config:set admin/usage/enabled 0" stepKey="disableAdminUsageTracking"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <waitForPageLoad stepKey="waitForPageReloaded"/> + <seeInPageSource html="var adminAnalyticsMetadata =" stepKey="seeInPageSource"/> + </test> +</tests> diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminNavigateToEmailToFriendSettingsActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminNavigateToEmailToFriendSettingsActionGroup.xml new file mode 100644 index 0000000000000..05903581747d9 --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminNavigateToEmailToFriendSettingsActionGroup.xml @@ -0,0 +1,15 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminNavigateToEmailToFriendSettingsActionGroup"> + <amOnPage url="{{AdminConfigurationEmailToFriendPage.url}}" stepKey="navigateToPersistencePage"/> + <conditionalClick selector="{{AdminEmailToFriendSection.DefaultLayoutsTab}}" dependentSelector="{{AdminEmailToFriendSection.CheckIfTabExpand}}" visible="true" stepKey="clickTab"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminEmailToFriendOptionsAvailableActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminEmailToFriendOptionsAvailableActionGroup.xml new file mode 100644 index 0000000000000..88152a2cb4f73 --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminEmailToFriendOptionsAvailableActionGroup.xml @@ -0,0 +1,18 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertAdminEmailToFriendOptionsAvailableActionGroup"> + <seeElement stepKey="seeEmailTemplateInput" selector="{{AdminEmailToFriendSection.emailTemplate}}"/> + <seeElement stepKey="seeAllowForGuestsInput" selector="{{AdminEmailToFriendSection.allowForGuests}}"/> + <seeElement stepKey="seeMaxRecipientsInput" selector="{{AdminEmailToFriendSection.maxRecipients}}"/> + <seeElement stepKey="seeMaxPerHourInput" selector="{{AdminEmailToFriendSection.maxPerHour}}"/> + <seeElement stepKey="seeLimitSendingBy" selector="{{AdminEmailToFriendSection.limitSendingBy}}"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminPageIs404ActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminPageIs404ActionGroup.xml new file mode 100644 index 0000000000000..09b0bdcc146ae --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminPageIs404ActionGroup.xml @@ -0,0 +1,18 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertAdminPageIs404ActionGroup"> + <annotations> + <description>Validates that the '404 Error' message is present in the current Admin Page Header.</description> + </annotations> + + <see userInput="404 Error" selector="{{AdminHeaderSection.pageHeading}}" stepKey="see404PageHeading"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationEmailToFriendPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationEmailToFriendPage.xml new file mode 100644 index 0000000000000..14bd514f1a16f --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationEmailToFriendPage.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="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminConfigurationEmailToFriendPage" url="admin/system_config/edit/section/sendfriend/" module="Catalog" area="admin"> + <section name="AdminEmailToFriendSection"/> + </page> +</pages> diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminCatalogEmailToFriendSettingsTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminCatalogEmailToFriendSettingsTest.xml new file mode 100644 index 0000000000000..b410a4cb73de7 --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminCatalogEmailToFriendSettingsTest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCatalogEmailToFriendSettingsTest"> + <annotations> + <features value="Backend"/> + <stories value="Enable Email To A Friend Functionality"/> + <title value="Admin should be able to manage settings of Email To A Friend Functionality"/> + <description value="Admin should be able to enable Email To A Friend functionality in Magento Admin backend and see additional options"/> + <group value="backend"/> + <severity value="MINOR"></severity> + <testCaseId value="MC-35895"/> + </annotations> + + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <magentoCLI stepKey="enableSendFriend" command="config:set sendfriend/email/enabled 1"/> + <magentoCLI stepKey="cacheClean" command="cache:clean config"/> + </before> + <after> + <magentoCLI stepKey="disableSendFriend" command="config:set sendfriend/email/enabled 0"/> + <magentoCLI stepKey="cacheClean" command="cache:clean config"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <actionGroup ref="AdminNavigateToEmailToFriendSettingsActionGroup" stepKey="navigateToSendFriendSettings"/> + <actionGroup ref="AssertAdminEmailToFriendOptionsAvailableActionGroup" stepKey="assertOptions"/> + </test> +</tests> diff --git a/app/code/Magento/Captcha/CustomerData/Captcha.php b/app/code/Magento/Captcha/CustomerData/Captcha.php index e07bf953abaa3..901477c75610b 100644 --- a/app/code/Magento/Captcha/CustomerData/Captcha.php +++ b/app/code/Magento/Captcha/CustomerData/Captcha.php @@ -58,7 +58,7 @@ public function __construct( /** * @inheritdoc */ - public function getSectionData() :array + public function getSectionData(): array { $data = []; diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml index c35e775152ac9..c94bca1ca5c13 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml @@ -12,7 +12,7 @@ <element name="collapseAll" type="button" selector=".tree-actions a:first-child"/> <element name="expandAll" type="button" selector=".tree-actions a:last-child"/> <element name="categoryHighlighted" type="text" selector="//div[@id='store.menu']//span[contains(text(),'{{name}}')]/ancestor::li" parameterized="true" timeout="30"/> - <element name="categoryNotHighlighted" type="text" selector="ul[id=\'ui-id-2\'] li[class~=\'active\']" timeout="30"/> + <element name="categoryNotHighlighted" type="text" selector="[id=\'store.menu\'] ul li.active" timeout="30"/> <element name="categoryTreeRoot" type="text" selector="div.x-tree-root-node>li.x-tree-node:first-of-type>div.x-tree-node-el:first-of-type" timeout="30"/> <element name="categoryInTree" type="text" selector="//a/span[contains(text(), '{{name}}')]" parameterized="true" timeout="30"/> <element name="categoryInTreeUnderRoot" type="text" selector="//li/ul/li[@class='x-tree-node']/div/a/span[contains(text(), '{{name}}')]" parameterized="true"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml index 4e86f14611c24..201affacd9adb 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml @@ -38,5 +38,6 @@ <element name="storeViewDropdown" type="text" selector="//select[@name='store_id']/option[contains(.,'{{storeView}}')]" parameterized="true"/> <element name="inputByCodeRangeFrom" type="input" selector="input.admin__control-text[name='{{code}}[from]']" parameterized="true"/> <element name="inputByCodeRangeTo" type="input" selector="input.admin__control-text[name='{{code}}[to]']" parameterized="true"/> + <element name="storeViewOptions" type="text" selector=".admin__data-grid-outer-wrap select[name='store_id'] > option[value='{{value}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontFooterSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontFooterSection.xml index 1c937637ad823..a7dd622c56a7f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontFooterSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontFooterSection.xml @@ -9,6 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="StorefrontFooterSection"> <element name="switchStoreButton" type="button" selector="#switcher-store-trigger"/> + <element name="storeViewOptionNumber" type="button" selector="//div[@class='actions dropdown options switcher-options active']//ul//li[{{var1}}]//a" parameterized="true"/> <element name="storeLink" type="button" selector="//ul[@class='dropdown switcher-dropdown']//a[contains(text(),'{{var1}}')]" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridUrlFilterApplierTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridUrlFilterApplierTest.xml index fea4436446da2..2eda7b8d02481 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridUrlFilterApplierTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridUrlFilterApplierTest.xml @@ -31,11 +31,11 @@ <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin"/> </after> - <amOnPage url="{{AdminProductIndexPage.url}}?filters[name]=$createSimpleProduct.name$" stepKey="navigateToProductGridWithFilters"/> + <amOnPage url="{{AdminProductIndexPage.url}}?filters[sku]=$createSimpleProduct.sku$" stepKey="navigateToProductGridWithFilters"/> <waitForPageLoad stepKey="waitForProductGrid"/> <see selector="{{AdminProductGridSection.productGridNameProduct($createSimpleProduct.name$)}}" userInput="$createSimpleProduct.name$" stepKey="seeProduct"/> <waitForElementVisible selector="{{AdminProductGridFilterSection.enabledFilters}}" stepKey="waitForEnabledFilters"/> <seeElement selector="{{AdminProductGridFilterSection.enabledFilters}}" stepKey="seeEnabledFilters"/> - <see selector="{{AdminProductGridFilterSection.enabledFilters}}" userInput="Name: $createSimpleProduct.name$" stepKey="seeProductNameFilter"/> + <see selector="{{AdminProductGridFilterSection.enabledFilters}}" userInput="SKU: $createSimpleProduct.sku$" stepKey="seeProductNameFilter"/> </test> </tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StoreFrontRecentlyComparedAtWebsiteLevelTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StoreFrontRecentlyComparedAtWebsiteLevelTest.xml deleted file mode 100644 index 7ec5fea49f64b..0000000000000 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StoreFrontRecentlyComparedAtWebsiteLevelTest.xml +++ /dev/null @@ -1,108 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="StoreFrontRecentlyComparedAtWebsiteLevelTest"> - <annotations> - <features value="Catalog"/> - <stories value="Recently Compared Product"/> - <title value="Recently Compared Product at website level"/> - <description value="Recently Compared Products widget appears on a page immediately after adding product to compare"/> - <severity value="MAJOR"/> - <testCaseId value="MC-33099"/> - <useCaseId value="MC-32763"/> - <group value="catalog"/> - <group value="widget"/> - <skip> - <issueId value="MC-34091"/> - </skip> - </annotations> - <before> - <!-- Set Stores > Configurations > Catalog > Recently Viewed/Compared Products > Show for Current = Website --> - <magentoCLI command="config:set {{RecentlyViewedProductScopeWebsite.path}} {{RecentlyViewedProductScopeWebsite.value}}" stepKey="setRecentlyViewedComparedProductsScopeToWebsite"/> - <!--Create Simple Products and Category --> - <createData entity="SimpleSubCategory" stepKey="createCategory"/> - <createData entity="SimpleProduct" stepKey="createSimpleProductToCompareFirst"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <createData entity="SimpleProduct" stepKey="createSimpleProductToCompareSecond"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <createData entity="SimpleProduct" stepKey="createSimpleProductNotVisibleFirst"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <createData entity="SimpleProduct" stepKey="createSimpleProductNotVisibleSecond"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <createData entity="Simple_US_Customer" stepKey="createCustomer"/> - <!-- Login as admin --> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - <!-- Create product widget --> - <actionGroup ref="AdminCreateRecentlyProductsWidgetActionGroup" stepKey="createRecentlyComparedProductsWidget"> - <argument name="widget" value="RecentlyComparedProductsWidget"/> - </actionGroup> - </before> - <after> - <!-- Reset Stores > Configurations > Catalog > Recently Viewed/Compared Products > Show for Current = Website--> - <magentoCLI command="config:set {{RecentlyViewedProductScopeWebsite.path}} {{RecentlyViewedProductScopeWebsite.value}}" stepKey="setRecentlyViewedComparedProductsScopeToDefault"/> - <!-- Delete Products and Category --> - <deleteData createDataKey="createSimpleProductToCompareFirst" stepKey="deleteSimpleProductToCompareFirst"/> - <deleteData createDataKey="createSimpleProductToCompareSecond" stepKey="deleteSimpleProductToCompareSecond"/> - <deleteData createDataKey="createSimpleProductNotVisibleFirst" stepKey="deleteSimpleProductNotVisibleFirst"/> - <deleteData createDataKey="createSimpleProductNotVisibleSecond" stepKey="deleteSimpleProductNotVisibleSecond"/> - <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <!-- Customer Logout --> - <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="logoutFromCustomer"/> - <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> - <!-- Delete product widget --> - <actionGroup ref="AdminDeleteWidgetActionGroup" stepKey="deleteRecentlyComparedProductsWidget"> - <argument name="widget" value="RecentlyComparedProductsWidget"/> - </actionGroup> - <!-- Logout Admin --> - <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> - </after> - <!--Login to storefront from customer--> - <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginCustomer"> - <argument name="Customer" value="$createCustomer$"/> - </actionGroup> - <see userInput="Welcome, $createCustomer.firstname$ $createCustomer.lastname$!" selector="{{StorefrontPanelHeaderSection.welcomeMessage}}" stepKey="checkWelcomeMessage"/> - <amOnPage url="{{StorefrontCategoryPage.url($createCategory.custom_attributes[url_key]$)}}" stepKey="openCategoryPage"/> - <!--Add to compare Simple Product and Simple Product 2--> - <actionGroup ref="StorefrontAddCategoryProductToCompareActionGroup" stepKey="addSimpleProduct1ToCompare" > - <argument name="productVar" value="$createSimpleProductToCompareFirst$"/> - </actionGroup> - <actionGroup ref="StorefrontAddCategoryProductToCompareActionGroup" stepKey="addSimpleProduct2ToCompare" > - <argument name="productVar" value="$createSimpleProductToCompareSecond$"/> - </actionGroup> - <!--The Compare Products widget displays Simple Product 1 and Simple Product 2--> - <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="checkSimpleProduct1InCompareSidebar"> - <argument name="productVar" value="$createSimpleProductToCompareFirst$"/> - </actionGroup> - <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="checkSimpleProduct2InCompareSidebar"> - <argument name="productVar" value="$createSimpleProductToCompareSecond$"/> - </actionGroup> - - <!--Click Clear all in the Compare Products widget--> - <actionGroup ref="StorefrontClearCompareActionGroup" stepKey="clearCompareList"/> - <!--The Recently Compared widget displays Simple Product 1 and Simple Product 2--> - <waitForPageLoad stepKey="waitForRecentlyComparedWidgetLoad"/> - <actionGroup ref="StorefrontAssertProductInRecentlyComparedWidgetActionGroup" stepKey="checkSimpleProduct1ExistInRecentlyComparedWidget"> - <argument name="product" value="$createSimpleProductToCompareFirst$"/> - </actionGroup> - <actionGroup ref="StorefrontAssertProductInRecentlyComparedWidgetActionGroup" stepKey="checkSimpleProduct2ExistInRecentlyComparedWidget"> - <argument name="product" value="$createSimpleProductToCompareSecond$"/> - </actionGroup> - <!--The Recently Compared widget not displays Simple Product 3 and Simple Product 4--> - <actionGroup ref="StorefrontAssertNotExistProductInRecentlyComparedWidgetActionGroup" stepKey="checkSimpleProduct3NotExistInRecentlyComparedWidget"> - <argument name="product" value="$createSimpleProductNotVisibleFirst$"/> - </actionGroup> - <actionGroup ref="StorefrontAssertNotExistProductInRecentlyComparedWidgetActionGroup" stepKey="checkSimpleProduct4NotExistInRecentlyComparedWidget"> - <argument name="product" value="$createSimpleProductNotVisibleSecond$"/> - </actionGroup> - </test> -</tests> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutActionGroup.xml new file mode 100644 index 0000000000000..8210fe1df73ba --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutActionGroup.xml @@ -0,0 +1,19 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutActionGroup"> + <annotations> + <description>Checks if visible password field for unregistered email on checkout page</description> + </annotations> + + <waitForPageLoad stepKey="waitForCheckoutPageLoaded"/> + <dontSeeElement selector="{{StorefrontCheckoutCheckoutCustomerLoginSection.password}}" stepKey="checkIfPasswordVisible"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutErrorMessageActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutErrorMessageActionGroup.xml new file mode 100644 index 0000000000000..6db9d9a1f0673 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutErrorMessageActionGroup.xml @@ -0,0 +1,18 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontAssertCheckoutErrorMessageActionGroup"> + <arguments> + <argument name="message" type="string"/> + </arguments> + + <waitForElementVisible selector="{{CheckoutCartMessageSection.errorMessageText(message)}}" stepKey="assertErrorMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartMessageSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartMessageSection.xml index cf15cdf15cf15..0c7f200e2b5eb 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartMessageSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartMessageSection.xml @@ -12,5 +12,6 @@ <element name="successMessage" type="text" selector=".message.message-success.success>div" /> <element name="errorMessage" type="text" selector=".message-error.error.message>div" /> <element name="emptyCartMessage" type="text" selector=".cart-empty>p"/> + <element name="errorMessageText" type="text" selector="//div[contains(@class, 'message-error')]/div[text()='{{var}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutTest.xml new file mode 100644 index 0000000000000..41b5f734d0096 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutTest.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutTest"> + <annotations> + <features value="Checkout"/> + <stories value="Visible password field for unregistered e-mail on Checkout"/> + <title value="Visibility password field for unregistered e-mail on Checkout process"/> + <description value="Guest should not be able to see password field if entered unregistered email"/> + <severity value="MINOR"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="SimpleTwo" stepKey="simpleProduct"/> + </before> + <after> + <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> + </after> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductStorefront"> + <argument name="productUrl" value="$$simpleProduct.custom_attributes[url_key]$$"/> + </actionGroup> + <actionGroup ref="StorefrontClickAddToCartOnProductPageActionGroup" stepKey="addToCartFromStorefrontProductPage"/> + <actionGroup ref="StorefrontOpenCheckoutPageActionGroup" stepKey="openCheckoutPage"/> + <actionGroup ref="AssertStorefrontEmailTooltipContentOnCheckoutActionGroup" stepKey="assertEmailTooltipContent"/> + <actionGroup ref="AssertStorefrontEmailNoteMessageOnCheckoutActionGroup" stepKey="assertEmailNoteMessage"/> + <actionGroup ref="StorefrontFillEmailFieldOnCheckoutActionGroup" stepKey="fillUnregisteredEmailFirstAttempt"> + <argument name="email" value="unregistered@email.test"/> + </actionGroup> + <actionGroup ref="AssertStorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutActionGroup" stepKey="checkIfPasswordVisibleAfterFieldFilling"/> + <actionGroup ref="StorefrontOpenCheckoutPageActionGroup" stepKey="reloadCheckoutPage" /> + <actionGroup ref="AssertStorefrontVisiblePasswordFieldForUnregisteredEmailOnCheckoutActionGroup" + stepKey="checkIfPasswordVisibleAfterPageReload"/> + </test> +</tests> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js index 9adfb549a5b1c..8311d97522980 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js @@ -113,6 +113,7 @@ define([ $.when(this.isEmailCheckComplete).done(function () { this.isPasswordVisible(false); + checkoutData.setCheckedEmailValue(''); }.bind(this)).fail(function () { this.isPasswordVisible(true); checkoutData.setCheckedEmailValue(this.email()); @@ -192,6 +193,10 @@ define([ * @returns {Boolean} - initial visibility state. */ resolveInitialPasswordVisibility: function () { + if (checkoutData.getInputFieldEmailValue() !== '' && checkoutData.getCheckedEmailValue() !== '') { + return true; + } + if (checkoutData.getInputFieldEmailValue() !== '') { return checkoutData.getInputFieldEmailValue() === checkoutData.getCheckedEmailValue(); } diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminEmailToFriendSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminEmailToFriendSection.xml new file mode 100644 index 0000000000000..956316ed5cb46 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminEmailToFriendSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminEmailToFriendSection"> + <element name="DefaultLayoutsTab" type="button" selector=".entry-edit-head-link"/> + <element name="CheckIfTabExpand" type="button" selector=".entry-edit-head-link:not(.open)"/> + <element name="emailTemplate" type="input" selector="#sendfriend_email_template"/> + <element name="allowForGuests" type="input" selector="#sendfriend_email_allow_guest"/> + <element name="maxRecipients" type="input" selector="#sendfriend_email_max_recipients"/> + <element name="maxPerHour" type="input" selector="#sendfriend_email_max_per_hour"/> + <element name="limitSendingBy" type="input" selector="#sendfriend_email_check_by"/> + </section> +</sections> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index cf0e99f7c45c0..37c129dc3bbde 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -13,6 +13,7 @@ <element name="selectableProductOptions" type="select" selector="#attribute{{var1}} option:not([disabled])" parameterized="true"/> <element name="productAttributeTitle1" type="text" selector="#product-options-wrapper div[tabindex='0'] label"/> <element name="productPrice" type="text" selector="div.price-box.price-final_price"/> + <element name="tierPriceBlock" type="block" selector="div[data-role='tier-price-block']"/> <element name="productAttributeOptions1" type="select" selector="#product-options-wrapper div[tabindex='0'] option"/> <element name="productAttributeOptionsSelectButton" type="select" selector="#product-options-wrapper .super-attribute-select"/> <element name="productAttributeOptionsError" type="text" selector="//div[@class='mage-error']"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml index 1491081a82ee4..4de01b0c9d14e 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml @@ -48,7 +48,7 @@ <!--Add tier price in one product --> <createData entity="tierProductPrice" stepKey="addTierPrice"> - <requiredEntity createDataKey="createFirstSimpleProduct" /> + <requiredEntity createDataKey="createFirstSimpleProduct" /> </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> @@ -109,5 +109,8 @@ <expectedResult type="string">Buy {{tierProductPrice.quantity}} for ${{tierProductPrice.price}} each and save 27%</expectedResult> <actualResult type="variable">tierPriceText</actualResult> </assertEquals> + <seeElement selector="{{StorefrontProductInfoMainSection.tierPriceBlock}}" stepKey="seeTierPriceBlock"/> + <selectOption userInput="$$createConfigProductAttributeOptionTwo.option[store_labels][1][label]$$" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption2"/> + <dontSeeElement selector="{{StorefrontProductInfoMainSection.tierPriceBlock}}" stepKey="dontSeeTierPriceBlock"/> </test> </tests> diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js index f705b6a95987c..00030be74324f 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js @@ -740,21 +740,19 @@ define([ * @private */ _displayTierPriceBlock: function (optionId) { - var options, tierPriceHtml; + var tierPrices = typeof optionId != 'undefined' && this.options.spConfig.optionPrices[optionId].tierPrices; - if (typeof optionId != 'undefined' && - this.options.spConfig.optionPrices[optionId].tierPrices != [] // eslint-disable-line eqeqeq - ) { - options = this.options.spConfig.optionPrices[optionId]; + if (_.isArray(tierPrices) && tierPrices.length > 0) { if (this.options.tierPriceTemplate) { - tierPriceHtml = mageTemplate(this.options.tierPriceTemplate, { - 'tierPrices': options.tierPrices, - '$t': $t, - 'currencyFormat': this.options.spConfig.currencyFormat, - 'priceUtils': priceUtils - }); - $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show(); + $(this.options.tierPriceBlockSelector).html( + mageTemplate(this.options.tierPriceTemplate, { + 'tierPrices': tierPrices, + '$t': $t, + 'currencyFormat': this.options.spConfig.currencyFormat, + 'priceUtils': priceUtils + }) + ).show(); } } else { $(this.options.tierPriceBlockSelector).hide(); diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminClickFirstRowEditLinkOnCustomerGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminClickFirstRowEditLinkOnCustomerGridActionGroup.xml new file mode 100644 index 0000000000000..0cfe9f80d1619 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminClickFirstRowEditLinkOnCustomerGridActionGroup.xml @@ -0,0 +1,19 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminClickFirstRowEditLinkOnCustomerGridActionGroup"> + <annotations> + <description>Click edit link for first row on the grid.</description> + </annotations> + + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditLink"/> + <waitForPageLoad stepKey="waitForPageLoading"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml index c8e3bc10cc769..9f6d8d645e5f4 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml @@ -50,8 +50,7 @@ <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> <!--Assert Customer Form --> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> <see selector="{{AdminCustomerAccountInformationSection.groupIdValue}}" userInput="Retailer" stepKey="seeCustomerGroup1"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml index 5f496e2c5fba3..782c1599bf489 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml @@ -31,8 +31,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton"/> <!-- Add the Address --> <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="selectAddress"/> @@ -67,8 +66,7 @@ <see userInput="{{PolandAddress.telephone}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertPhoneNumber"/> <!--Assert Customer Form --> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="$$createCustomer.firstname$$" stepKey="seeCustomerFirstName"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml index da2eed2006434..304d545fb4c93 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml @@ -31,8 +31,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton"/> <!-- Add the Address --> <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="selectAddress"/> @@ -67,8 +66,7 @@ <see userInput="{{US_Address_CA.telephone}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertPhoneNumber"/> <!--Assert Customer Form --> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="$$createCustomer.firstname$$" stepKey="seeCustomerFirstName"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml index 8afd1648d26e0..7cffd5f304e31 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml @@ -54,8 +54,7 @@ <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> <!--Assert Customer Form --> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> <see selector="{{AdminCustomerAccountInformationSection.groupIdValue}}" userInput="$$customerGroup.code$$" stepKey="seeCustomerGroup1"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml index e9250be637534..eaa3a11edb74e 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml @@ -56,8 +56,7 @@ <see userInput="Male" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertGender"/> <!--Assert Customer Form --> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> <seeInField selector="{{AdminCustomerAccountInformationSection.namePrefix}}" userInput="{{CustomerEntityOne.prefix}}" stepKey="seeCustomerNamePrefix"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml index 5033f2882af42..98826b147ad81 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml @@ -49,8 +49,7 @@ <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> <!--Assert Customer Form --> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="seeCustomerFirstName"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerOnStorefrontSignupNewsletterTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerOnStorefrontSignupNewsletterTest.xml index 5440339e3a95e..683b275ca1ed6 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerOnStorefrontSignupNewsletterTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerOnStorefrontSignupNewsletterTest.xml @@ -45,8 +45,7 @@ <see selector="{{AdminCustomerGridSection.customerGrid}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeAssertCustomerEmailInGrid"/> <!--Assert verify created new customer is subscribed to newsletter--> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickFirstRowEditLink"/> - <waitForPageLoad stepKey="waitForEditLinkLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickFirstRowEditLink"/> <click selector="{{AdminEditCustomerInformationSection.newsLetter}}" stepKey="clickNewsLetter"/> <waitForPageLoad stepKey="waitForNewsletterTabToOpen"/> <seeCheckboxIsChecked selector="{{AdminEditCustomerNewsletterSection.subscribedStatus('1')}}" stepKey="seeAssertSubscribedToNewsletterCheckboxIsChecked"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml index 6b484e857d276..5edb9d08da46d 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml @@ -42,8 +42,7 @@ <argument name="email" value="{{CustomerEntityOne.email}}"/> </actionGroup> <waitForPageLoad stepKey="waitForPageToLoad"/> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> - <waitForPageLoad stepKey="waitForCustomerEditPageToLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickOnEditButton1"/> <!-- Assert Customer Title --> <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCustomerSubscribeNewsletterPerWebsiteTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCustomerSubscribeNewsletterPerWebsiteTest.xml index a8391458a1a50..87111ec6fba1a 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCustomerSubscribeNewsletterPerWebsiteTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCustomerSubscribeNewsletterPerWebsiteTest.xml @@ -53,8 +53,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCustomerGrid"> <argument name="email" value="{{CustomerEntityOne.email}}"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickToEditCustomerPage"/> - <waitForPageLoad stepKey="waitForOpenCustomerPage"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickToEditCustomerPage"/> <grabFromCurrentUrl regex="~(\d+)/~" stepKey="grabCustomerId"/> <!-- Assert that created customer is subscribed to newsletter on the new Store View --> <actionGroup ref="AdminAssertCustomerIsSubscribedToNewslettersAndSelectedStoreView" stepKey="assertSubscribedToNewsletter"> diff --git a/app/code/Magento/MediaGallery/Model/Directory/Command/CreateByPaths.php b/app/code/Magento/MediaGallery/Model/Directory/Command/CreateByPaths.php index f33c22a18b4b8..d0ba786c7084e 100644 --- a/app/code/Magento/MediaGallery/Model/Directory/Command/CreateByPaths.php +++ b/app/code/Magento/MediaGallery/Model/Directory/Command/CreateByPaths.php @@ -78,7 +78,7 @@ public function execute(array $paths): void if (!empty($failedPaths)) { throw new CouldNotSaveException( __( - 'Could not save directories: %paths', + 'Could not create directories: %paths', [ 'paths' => implode(' ,', $failedPaths) ] diff --git a/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/ActionGroup/AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup.xml b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/ActionGroup/AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup.xml new file mode 100644 index 0000000000000..e21fa89965391 --- /dev/null +++ b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/ActionGroup/AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup.xml @@ -0,0 +1,20 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup"> + <annotations> + <description>Assert asset filter placeholder value</description> + </annotations> + <arguments> + <argument name="filterPlaceholder" type="string"/> + </arguments> + + <see selector="{{AdminProductGridFilterSection.enabledFilters}}" userInput="{{filterPlaceholder}}" stepKey="seeFilter"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiUsedInProductFilterTest.xml b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiUsedInProductFilterTest.xml index 74633fbb73542..c3f3d6ecd9e8d 100644 --- a/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiUsedInProductFilterTest.xml +++ b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiUsedInProductFilterTest.xml @@ -10,27 +10,22 @@ <test name="AdminMediaGalleryCatalogUiUsedInProductFilterTest"> <annotations> <features value="AdminMediaGalleryUsedInProductsFilter"/> - <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1168"/> - <title value="Used in products filter"/> + <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1503"/> + <title value="User can open product entity the asset is associated"/> <stories value="Story 58: User sees entities where asset is used in" /> - <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4951848"/> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/943908/scenarios/4523889"/> <description value="User filters assets used in products"/> <severity value="CRITICAL"/> <group value="media_gallery_ui"/> </annotations> <before> <magentoCLI command="config:set cms/wysiwyg/enabled enabled" stepKey="enableWYSIWYG"/> - <createData entity="SimpleSubCategory" stepKey="category"/> - <createData entity="SimpleProduct" stepKey="product"> - <requiredEntity createDataKey="category"/> - </createData> + <createData entity="SimpleProduct2" stepKey="product"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> <after> <magentoCLI command="config:set cms/wysiwyg/enabled disabled" stepKey="disableWYSIWYG"/> <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> - <deleteData createDataKey="product" stepKey="deleteProduct"/> - <deleteData createDataKey="category" stepKey="deleteCategory"/> </after> <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchProduct"> <argument name="product" value="$$product$$"/> @@ -38,11 +33,7 @@ <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> <argument name="product" value="$$product$$"/> </actionGroup> - <click selector="{{AdminProductFormSection.contentTab}}" stepKey="clickContentTab"/> - <waitForElementVisible selector="{{CatalogWYSIWYGSection.TinyMCE4}}" stepKey="waitForTinyMCE4" /> - <click selector="{{CatalogWYSIWYGSection.InsertImageIcon}}" stepKey="clickInsertImageIcon" /> - <waitForPageLoad stepKey="waitForPageLoad" /> - <actionGroup ref="ClickBrowseBtnOnUploadPopupActionGroup" stepKey="clickBrowserBtn"/> + <actionGroup ref="AdminOpenMediaGalleryTinyMce4ActionGroup" stepKey="openMediaGalleryFromWysiwyg"/> <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> <argument name="image" value="ImageUpload3"/> </actionGroup> @@ -59,17 +50,22 @@ <argument name="optionName" value="$$product.name$$"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryApplyFiltersActionGroup" stepKey="applyFilters"/> - <actionGroup ref="AdminMediaGalleryAssertImageInGridActionGroup" stepKey="assertImageInGrid"> - <argument name="title" value="ImageMetadata.title"/> + + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryClickEntityUsedInActionGroup" stepKey="clickUsedInProducts"> + <argument name="entityName" value="Products"/> </actionGroup> - <wait time="10" stepKey="waitForBookmarkToSaveView"/> - <reloadPage stepKey="reloadPage"/> - <waitForPageLoad stepKey="waitForGridReloaded"/> - <actionGroup ref="AdminAssertMediaGalleryFilterPlaceholderActionGroup" stepKey="assertFilterApplied"> + <actionGroup ref="AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup" stepKey="assertFilterApplied"> <argument name="filterPlaceholder" value="$$product.name$$"/> </actionGroup> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetailsToAssertEmptyUsedIn"/> + <actionGroup ref="AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup" stepKey="assertThereIsNoUsedInSection"/> + <actionGroup ref="AdminEnhancedMediaGalleryCloseViewDetailsActionGroup" stepKey="closeDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectFirstImageToDelete"> <argument name="imageName" value="{{ImageMetadata.title}}"/> diff --git a/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkCategoryGridTest.xml b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkCategoryGridTest.xml index 7e0fa6c477c45..5cb778dfb9c8c 100644 --- a/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkCategoryGridTest.xml +++ b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkCategoryGridTest.xml @@ -23,14 +23,12 @@ <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> <after> - <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectSecondImageToDelete"> <argument name="imageName" value="{{UpdatedImageDetails.title}}"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryClickDeleteImagesButtonActionGroup" stepKey="clikDeleteSelectedButton"/> <actionGroup ref="AdminEnhancedMediaGalleryConfirmDeleteImagesActionGroup" stepKey="deleteImages"/> - <deleteData createDataKey="category" stepKey="deleteCategory"/> </after> <actionGroup ref="AdminOpenCategoryPageActionGroup" stepKey="openCategoryPage"/> @@ -60,5 +58,22 @@ <actionGroup ref="AdminMediaGalleryAssertCategoryNameInCategoryGridActionGroup" stepKey="assertCategoryInGrid"> <argument name="categoryName" value="$$category.name$$"/> </actionGroup> + + <actionGroup ref="AdminEnhancedMediaGalleryCategoryGridExpandFilterActionGroup" stepKey="expandFilters"/> + <actionGroup ref="AdminEnhancedMediaGallerySelectUsedInFilterActionGroup" stepKey="setAssetFilter"> + <argument name="filterName" value="Asset"/> + <argument name="optionName" value="{{UpdatedImageDetails.title}}"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryCategoryGridApplyFiltersActionGroup" stepKey="applyFilters"/> + <actionGroup ref="AssertAdminMediaGalleryAssetFilterPlaceHolderActionGroup" stepKey="assertFilterAppliedAfterUrlFilterApplier"> + <argument name="filterPlaceholder" value="{{UpdatedImageDetails.title}}"/> + </actionGroup> + + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetailsToVerfifyEmptyUsedIn"/> + <actionGroup ref="AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup" stepKey="assertThereIsNoUsedInSection"/> + <actionGroup ref="AdminEnhancedMediaGalleryCloseViewDetailsActionGroup" stepKey="closeDetails"/> + </test> </tests> diff --git a/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkProductGridTest.xml b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkProductGridTest.xml new file mode 100644 index 0000000000000..db7942d4c53bf --- /dev/null +++ b/app/code/Magento/MediaGalleryCatalogUi/Test/Mftf/Test/AdminMediaGalleryCatalogUiVerifyUsedInLinkProductGridTest.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="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMediaGalleryCatalogUiVerifyUsedInLinkProductGridTest"> + <annotations> + <features value="AdminMediaGalleryUsedInProductsFilter"/> + <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1168"/> + <title value="Used in products filter"/> + <stories value="Story 58: User sees entities where asset is used in" /> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4951848"/> + <description value="User filters assets used in products"/> + <severity value="CRITICAL"/> + <group value="media_gallery_ui"/> + </annotations> + <before> + <magentoCLI command="config:set cms/wysiwyg/enabled enabled" stepKey="enableWYSIWYG"/> + <createData entity="SimpleSubCategory" stepKey="category"/> + <createData entity="SimpleProduct" stepKey="product"> + <requiredEntity createDataKey="category"/> + </createData> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <magentoCLI command="config:set cms/wysiwyg/enabled disabled" stepKey="disableWYSIWYG"/> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + </after> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchProduct"> + <argument name="product" value="$$product$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> + <argument name="product" value="$$product$$"/> + </actionGroup> + <click selector="{{AdminProductFormSection.contentTab}}" stepKey="clickContentTab"/> + <waitForElementVisible selector="{{CatalogWYSIWYGSection.TinyMCE4}}" stepKey="waitForTinyMCE4" /> + <click selector="{{CatalogWYSIWYGSection.InsertImageIcon}}" stepKey="clickInsertImageIcon" /> + <waitForPageLoad stepKey="waitForPageLoad" /> + <actionGroup ref="ClickBrowseBtnOnUploadPopupActionGroup" stepKey="clickBrowserBtn"/> + <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> + <argument name="image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryClickImageInGridActionGroup" stepKey="selectContentImageInGrid"> + <argument name="imageName" value="{{ImageMetadata.title}}"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryClickAddSelectedActionGroup" stepKey="clickAddSelectedContentImage"/> + <actionGroup ref="AdminMediaGalleryClickOkButtonTinyMce4ActionGroup" stepKey="clickOkButton"/> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct"/> + + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryClickEntityUsedInActionGroup" stepKey="clickUsedInProducts"> + <argument name="entityName" value="Products"/> + </actionGroup> + <actionGroup ref="AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup" stepKey="assertFilterApplied"> + <argument name="filterPlaceholder" value="{{ImageMetadata.title}}"/> + </actionGroup> + + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetailsToVerfifyEmptyUsedIn"/> + <actionGroup ref="AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup" stepKey="assertThereIsNoUsedInSection"/> + <actionGroup ref="AdminEnhancedMediaGalleryCloseViewDetailsActionGroup" stepKey="closeDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> + <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectFirstImageToDelete"> + <argument name="imageName" value="{{ImageMetadata.title}}"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryClickDeleteImagesButtonActionGroup" stepKey="clikDeleteSelectedButton"/> + <actionGroup ref="AdminEnhancedMediaGalleryConfirmDeleteImagesActionGroup" stepKey="deleteImages"/> + + </test> +</tests> diff --git a/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryAssertUsedInLinkBlocksGridTest.xml b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryAssertUsedInLinkBlocksGridTest.xml new file mode 100644 index 0000000000000..a0cd04fad54c5 --- /dev/null +++ b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryAssertUsedInLinkBlocksGridTest.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMediaGalleryAssertUsedInLinkBlocksGridTest"> + <annotations> + <features value="AdminMediaGalleryUsedInBlocksFilter"/> + <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1168"/> + <title value="Used in blocks link"/> + <stories value="Story 58: User sees entities where asset is used in" /> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4951848"/> + <description value="User filters assets used in blocks"/> + <severity value="CRITICAL"/> + <group value="media_gallery_ui"/> + </annotations> + <before> + <createData entity="_defaultBlock" stepKey="block" /> + <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> + </before> + <after> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> + </after> + + <actionGroup ref="NavigateToCreatedCMSBlockPageActionGroup" stepKey="navigateToCreatedCMSBlockPage1"> + <argument name="CMSBlockPage" value="$$block$$"/> + </actionGroup> + <click selector="{{CmsWYSIWYGSection.InsertImageBtn}}" stepKey="clickInsertImageIcon" /> + <waitForPageLoad stepKey="waitForPageLoad" /> + <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> + <argument name="image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryClickImageInGridActionGroup" stepKey="selectContentImageInGrid"> + <argument name="imageName" value="{{ImageMetadata.title}}"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryClickAddSelectedActionGroup" stepKey="clickAddSelectedContentImage"/> + <click selector="{{BlockNewPagePageActionsSection.saveBlock}}" stepKey="saveBlock"/> + + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryClickEntityUsedInActionGroup" stepKey="clickUsedInPages"> + <argument name="entityName" value="Blocks"/> + </actionGroup> + <actionGroup ref="AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup" stepKey="assertFilterApplied"> + <argument name="filterPlaceholder" value="{{ImageMetadata.title}}"/> + </actionGroup> + + <deleteData createDataKey="block" stepKey="deleteBlock"/> + + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetailsToVerfifyEmptyUsedIn"/> + <actionGroup ref="AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup" stepKey="assertThereIsNoUsedInSection"/> + <actionGroup ref="AdminEnhancedMediaGalleryCloseViewDetailsActionGroup" stepKey="closeDetails"/> + + <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> + <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectFirstImageToDelete"> + <argument name="imageName" value="{{ImageMetadata.title}}"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryClickDeleteImagesButtonActionGroup" stepKey="clikDeleteSelectedButton"/> + <actionGroup ref="AdminEnhancedMediaGalleryConfirmDeleteImagesActionGroup" stepKey="deleteImages"/> + </test> +</tests> diff --git a/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryAssertUsedInLinkPagesGridTest.xml b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryAssertUsedInLinkPagesGridTest.xml new file mode 100644 index 0000000000000..de8517eedae0e --- /dev/null +++ b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryAssertUsedInLinkPagesGridTest.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMediaGalleryAssertUsedInLinkPagesGridTest"> + <annotations> + <features value="AdminMediaGalleryUsedInBlocksFilter"/> + <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1168"/> + <title value="Used in pages link"/> + <stories value="Story 58: User sees entities where asset is used in" /> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4951848"/> + <description value="User filters assets used in pages"/> + <severity value="CRITICAL"/> + <group value="media_gallery_ui"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> + </before> + <after> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> + </after> + + <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToCreateNewPage"/> + <actionGroup ref="FillOutCustomCMSPageContentActionGroup" stepKey="fillBasicPageDataForPageWithDefaultStore"> + <argument name="title" value="Unique page title MediaGalleryUi"/> + <argument name="content" value="MediaGalleryUI content"/> + <argument name="identifier" value="test-page-1"/> + </actionGroup> + + <actionGroup ref="AdminOpenMediaGalleryFromPageNoEditorActionGroup" stepKey="openMediaGalleryForPage"/> + <waitForPageLoad stepKey="waitForPageLoad" /> + <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> + <argument name="image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryClickImageInGridActionGroup" stepKey="selectContentImageInGrid"> + <argument name="imageName" value="{{ImageMetadata.title}}"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryClickAddSelectedActionGroup" stepKey="clickAddSelectedContentImage"/> + <click selector="{{CmsNewPagePageActionsSection.saveAndContinueEdit}}" stepKey="savePage"/> + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryClickEntityUsedInActionGroup" stepKey="clickUsedInPages"> + <argument name="entityName" value="Pages"/> + </actionGroup> + <actionGroup ref="AdminAssertMediaGalleryFilterPlaceHolderGridActionGroup" stepKey="assertFilterApplied"> + <argument name="filterPlaceholder" value="{{ImageMetadata.title}}"/> + </actionGroup> + + <actionGroup ref="AdminDeleteCmsPageFromGridActionGroup" stepKey="deleteCmsPage"> + <argument name="urlKey" value="test-page-1"/> + </actionGroup> + + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="openViewImageDetailsToVerfifyEmptyUsedIn"/> + <actionGroup ref="AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup" stepKey="assertThereIsNoUsedInSection"/> + <actionGroup ref="AdminEnhancedMediaGalleryCloseViewDetailsActionGroup" stepKey="closeDetails"/> + + <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> + <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectFirstImageToDelete"> + <argument name="imageName" value="{{ImageMetadata.title}}"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryClickDeleteImagesButtonActionGroup" stepKey="clikDeleteSelectedButton"/> + <actionGroup ref="AdminEnhancedMediaGalleryConfirmDeleteImagesActionGroup" stepKey="deleteImages"/> + + </test> +</tests> diff --git a/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInBlocksFilterTest.xml b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInBlocksFilterTest.xml index 810d9eea4e261..fa6dc6c1a07fa 100644 --- a/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInBlocksFilterTest.xml +++ b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInBlocksFilterTest.xml @@ -55,6 +55,6 @@ </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryClickDeleteImagesButtonActionGroup" stepKey="clikDeleteSelectedButton"/> <actionGroup ref="AdminEnhancedMediaGalleryConfirmDeleteImagesActionGroup" stepKey="deleteImages"/> - + </test> </tests> diff --git a/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml index a6bfdb781a734..038f1ae077b4a 100644 --- a/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml +++ b/app/code/Magento/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml @@ -21,14 +21,14 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> </before> - + <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToCreateNewPage"/> <actionGroup ref="FillOutCustomCMSPageContentActionGroup" stepKey="fillBasicPageDataForPageWithDefaultStore"> <argument name="title" value="Unique page title MediaGalleryUi"/> <argument name="content" value="MediaGalleryUI content"/> <argument name="identifier" value="test-page-1"/> </actionGroup> - + <actionGroup ref="AdminOpenMediaGalleryFromPageNoEditorActionGroup" stepKey="openMediaGalleryForPage"/> <waitForPageLoad stepKey="waitForPageLoad" /> <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> @@ -39,7 +39,7 @@ </actionGroup> <actionGroup ref="AdminMediaGalleryClickAddSelectedActionGroup" stepKey="clickAddSelectedContentImage"/> <click selector="{{CmsNewPagePageActionsSection.saveAndContinueEdit}}" stepKey="savePage"/> - + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> <actionGroup ref="AdminEnhancedMediaGalleryExpandFilterActionGroup" stepKey="expandFilters"/> <actionGroup ref="AdminEnhancedMediaGallerySelectUsedInFilterActionGroup" stepKey="setUsedInFilter"> @@ -56,8 +56,9 @@ <argument name="imageName" value="{{ImageMetadata.title}}"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryClickDeleteImagesButtonActionGroup" stepKey="clikDeleteSelectedButton"/> - + <actionGroup ref="AdminNavigateToPageGridActionGroup" stepKey="navigateToCmsPageGrid"/> + <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearGridFilters"/> <actionGroup ref="AdminSearchCmsPageInGridByUrlKeyActionGroup" stepKey="findCreatedCmsPage"> <argument name="urlKey" value="test-page-1"/> </actionGroup> diff --git a/app/code/Magento/MediaGalleryUi/Controller/Adminhtml/Media/Index.php b/app/code/Magento/MediaGalleryUi/Controller/Adminhtml/Media/Index.php index 3660374243d16..8c5b3d4d3a9ac 100644 --- a/app/code/Magento/MediaGalleryUi/Controller/Adminhtml/Media/Index.php +++ b/app/code/Magento/MediaGalleryUi/Controller/Adminhtml/Media/Index.php @@ -12,6 +12,9 @@ use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Controller\ResultInterface; +use Magento\MediaContentApi\Model\Config; +use Magento\Backend\App\Action\Context; +use Magento\Backend\Model\View\Result\Forward; /** * Controller serving the media gallery content @@ -20,6 +23,24 @@ class Index extends Action implements HttpGetActionInterface { public const ADMIN_RESOURCE = 'Magento_Cms::media_gallery'; + /** + * @var Config + */ + private $config; + + /** + * Index constructor. + * @param Context $context + * @param Config $config + */ + public function __construct( + Context $context, + Config $config + ) { + parent::__construct($context); + $this->config = $config; + } + /** * Get the media gallery layout * @@ -27,6 +48,14 @@ class Index extends Action implements HttpGetActionInterface */ public function execute(): ResultInterface { + if (!$this->config->isEnabled()) { + /** @var Forward $resultForward */ + $resultForward = $this->resultFactory->create(ResultFactory::TYPE_FORWARD); + $resultForward->forward('noroute'); + + return $resultForward; + } + /** @var Page $resultPage */ $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); $resultPage->setActiveMenu('Magento_MediaGalleryUi::media_gallery') diff --git a/app/code/Magento/MediaGalleryUi/Model/Directories/GetFolderTree.php b/app/code/Magento/MediaGalleryUi/Model/Directories/GetFolderTree.php index f0998a3e120f2..c22165ba4e51f 100644 --- a/app/code/Magento/MediaGalleryUi/Model/Directories/GetFolderTree.php +++ b/app/code/Magento/MediaGalleryUi/Model/Directories/GetFolderTree.php @@ -7,13 +7,14 @@ namespace Magento\MediaGalleryUi\Model\Directories; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\ValidatorException; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\Read; use Magento\MediaGalleryApi\Api\IsPathExcludedInterface; /** - * Build folder tree structure by path + * Build media gallery folder tree structure by path */ class GetFolderTree { @@ -22,43 +23,45 @@ class GetFolderTree */ private $filesystem; - /** - * @var string - */ - private $path; - /** * @var IsPathExcludedInterface */ private $isPathExcluded; /** - * Constructor - * * @param Filesystem $filesystem - * @param string $path * @param IsPathExcludedInterface $isPathExcluded */ public function __construct( Filesystem $filesystem, - string $path, IsPathExcludedInterface $isPathExcluded ) { $this->filesystem = $filesystem; - $this->path = $path; $this->isPathExcluded = $isPathExcluded; } /** * Return directory folder structure in array * - * @param bool $skipRoot * @return array * @throws ValidatorException */ - public function execute(bool $skipRoot = true): array + public function execute(): array { - return $this->buildFolderTree($this->getDirectories(), $skipRoot); + $tree = [ + 'name' => 'root', + 'path' => '/', + 'children' => [] + ]; + $directories = $this->getDirectories(); + foreach ($directories as $idx => &$node) { + $node['children'] = []; + $result = $this->findParent($node, $tree); + $parent = &$result['treeNode']; + + $parent['children'][] = &$directories[$idx]; + } + return $tree['children']; } /** @@ -72,7 +75,7 @@ private function getDirectories(): array $directories = []; /** @var Read $directory */ - $directory = $this->filesystem->getDirectoryRead($this->path); + $directory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA); if (!$directory->isDirectory()) { return $directories; @@ -96,30 +99,6 @@ private function getDirectories(): array return $directories; } - /** - * Build folder tree structure by provided directories path - * - * @param array $directories - * @param bool $skipRoot - * @return array - */ - private function buildFolderTree(array $directories, bool $skipRoot): array - { - $tree = [ - 'name' => 'root', - 'path' => '/', - 'children' => [] - ]; - foreach ($directories as $idx => &$node) { - $node['children'] = []; - $result = $this->findParent($node, $tree); - $parent = & $result['treeNode']; - - $parent['children'][] =& $directories[$idx]; - } - return $skipRoot ? $tree['children'] : $tree; - } - /** * Find parent directory * diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryAssertMassActionModeNotActiveActionGroup.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryAssertMassActionModeNotActiveActionGroup.xml index a691f65387e8e..1ec2004b22f24 100644 --- a/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryAssertMassActionModeNotActiveActionGroup.xml +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryAssertMassActionModeNotActiveActionGroup.xml @@ -12,8 +12,8 @@ <annotations> <description>Asserts that massaction mode is terminated</description> </annotations> - + <dontSeeElement selector="{{AdminMediaGalleryHeaderButtonsSection.addSelected}}" stepKey="verifyAddSelectedButtonNotVisible"/> <dontSeeElement selector="{{AdminEnhancedMediaGalleryMassActionSection.totalSelected}}" stepKey="verifyTeminateMassAction"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup.xml new file mode 100644 index 0000000000000..62adffc931c16 --- /dev/null +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup.xml @@ -0,0 +1,18 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertAdminEnhancedMediaGalleryUsedInSectionNotDisplayedActionGroup"> + <annotations> + <description>Assert that's used in section not displayed in view details.</description> + </annotations> + + <dontSeeElement selector="{{AdminEnhancedMediaGalleryViewDetailsSection.usedIn}}" stepKey="assertImageIsDeleted"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AssertFolderIsChangedActionGroup.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AssertFolderIsChangedActionGroup.xml new file mode 100644 index 0000000000000..090dbed8b4f78 --- /dev/null +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/ActionGroup/AssertFolderIsChangedActionGroup.xml @@ -0,0 +1,25 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertFolderIsChangedActionGroup"> + <annotations> + <description>Assert that folder is changed</description> + </annotations> + <arguments> + <argument name="newSelectedFolder" type="string"/> + <argument name="oldSelectedFolder" type="string" defaultValue="{{AdminMediaGalleryFolderData.name}}"/> + </arguments> + + <assertNotEquals stepKey="assertNotEqual"> + <actualResult type="string">{{newSelectedFolder}}</actualResult> + <expectedResult type="string">{{oldSelectedFolder}}</expectedResult> + </assertNotEquals> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml index e63429677fbae..d6abe464048c7 100644 --- a/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml @@ -19,6 +19,7 @@ <element name="delete" type="button" selector="//div[@class='media-gallery-image-details-modal']//button[contains(@class, 'delete')]"/> <element name="confirmDelete" type="button" selector=".action-accept"/> <element name="createdAtDate" type="button" selector="//div[@class='attribute']/span[contains(text(), 'Created')]/following-sibling::div"/> + <element name="usedIn" type="button" selector="//div[@class='attribute']/span[contains(text(), 'Used In')]"/> <element name="updatedAtDate" type="button" selector="//div[@class='attribute']/span[contains(text(), 'Modified')]/following-sibling::div"/> <element name="addImage" type="button" selector=".add-image-action"/> <element name="cancel" type="button" selector="#image-details-action-cancel"/> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Suite/MediaGalleryUiDisabledSuite.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Suite/MediaGalleryUiDisabledSuite.xml new file mode 100644 index 0000000000000..727fbde3f17b6 --- /dev/null +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Suite/MediaGalleryUiDisabledSuite.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="MediaGalleryUiDisabledSuite"> + <include> + <group name="media_gallery_ui_disabled"/> + </include> + </suite> +</suites> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryDeleteImagesInBulkTest.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryDeleteImagesInBulkTest.xml index 94831b039b53a..63c0fbfeefbbf 100644 --- a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryDeleteImagesInBulkTest.xml +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryDeleteImagesInBulkTest.xml @@ -19,9 +19,17 @@ <group value="media_gallery_ui"/> </annotations> <before> + <createData entity="SimpleSubCategory" stepKey="category"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + <actionGroup ref="AdminOpenCategoryPageActionGroup" stepKey="openCategoryPage"/> + <actionGroup ref="AdminCategoriesOpenCategoryActionGroup" stepKey="openCategory"> + <argument name="category" value="$$category$$"/> + </actionGroup> + <actionGroup ref="AdminOpenMediaGalleryFromCategoryImageUploaderActionGroup" stepKey="openMediaGalleryFromWysiwyg"/> </before> + <after> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + </after> <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> <argument name="image" value="ImageUpload"/> </actionGroup> @@ -34,7 +42,7 @@ <argument name="imageName" value="{{ImageUpload.fileName}}"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryDisableMassactionModeActionGroup" stepKey="disableMassActionMode"/> - + <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectFirstImageToDelete"> <argument name="imageName" value="{{ImageUpload.fileName}}"/> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGallerySwitchingBetweenViewsTest.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGallerySwitchingBetweenViewsTest.xml new file mode 100644 index 0000000000000..01b8c27b7371d --- /dev/null +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGallerySwitchingBetweenViewsTest.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMediaGallerySwitchingBetweenViewsTest"> + <annotations> + <features value="MediaGallery"/> + <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1523"/> + <title value="User switches between Views and checks if the folder is changed"/> + <stories value="User switches between Views and checks if the folder is changed"/> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1337102/scenarios/5060037"/> + <description value="User switches between Views and checks if the folder is changed"/> + <severity value="CRITICAL"/> + <group value="media_gallery_ui"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> + <actionGroup ref="AdminEnhancedMediaGalleryDeleteGridViewActionGroup" stepKey="deleteView"> + <argument name="viewToDelete" value="New View"/> + </actionGroup> + <actionGroup ref="AdminMediaGalleryFolderSelectActionGroup" stepKey="selectFolderForDelete"/> + <actionGroup ref="AdminMediaGalleryFolderDeleteActionGroup" stepKey="deleteFolder"/> + <actionGroup ref="AdminMediaGalleryAssertFolderDoesNotExistActionGroup" stepKey="assertFolderWasDeleted"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + </after> + <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="openNewPage"/> + <actionGroup ref="AdminOpenMediaGalleryFromPageNoEditorActionGroup" stepKey="openMediaGalleryForPage"/> + <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearFilters"/> + <actionGroup ref="AdminMediaGalleryOpenNewFolderFormActionGroup" stepKey="openNewFolderForm"/> + <actionGroup ref="AdminMediaGalleryCreateNewFolderActionGroup" stepKey="createNewFolder"/> + <actionGroup ref="AdminMediaGalleryAssertFolderNameActionGroup" stepKey="assertNewFolderCreated"/> + <waitForLoadingMaskToDisappear stepKey="waitForFolderContents"/> + <actionGroup ref="AdminEnhancedMediaGallerySaveCustomViewActionGroup" stepKey="saveCustomView"> + <argument name="viewName" value="New View"/> + </actionGroup> + <actionGroup ref="AdminOpenCategoryPageActionGroup" stepKey="openCategoryPage"/> + <actionGroup ref="AdminCategoriesOpenCategoryActionGroup" stepKey="openCategory"> + <argument name="category" value="$$category$$"/> + </actionGroup> + <actionGroup ref="AdminOpenMediaGalleryFromCategoryImageUploaderActionGroup" stepKey="openMediaGalleryFromImageUploader"/> + <actionGroup ref="AdminEnhancedMediaGallerySelectCustomBookmarksViewActionGroup" stepKey="selectDefaultView"> + <argument name="selectView" value="Default View"/> + </actionGroup> + <actionGroup ref="AssertFolderIsChangedActionGroup" stepKey="assertFolderIsChanged"> + <argument name="newSelectedFolder" value="category" /> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGallerySelectCustomBookmarksViewActionGroup" stepKey="switchBackToNewView"> + <argument name="selectView" value="New View"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryAssertActiveFiltersActionGroup" stepKey="assertFilterApplied"> + <argument name="resultValue" value="{{AdminMediaGalleryFolderData.name}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml index ca7a71258fead..3dd294fa50605 100644 --- a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml @@ -36,6 +36,7 @@ <actionGroup ref="AddCategoryImageActionGroup" stepKey="addCategoryImage"/> <actionGroup ref="AdminSaveCategoryFormActionGroup" stepKey="saveCategoryForm"/> <actionGroup ref="AdminOpenMediaGalleryFromCategoryImageUploaderActionGroup" stepKey="openMediaGalleryFromImageUploader"/> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> <actionGroup ref="AdminMediaGalleryAssertImageInGridActionGroup" stepKey="assertImageInGrid"> <argument name="title" value="ProductImage.filename"/> </actionGroup> diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminStandaloneMediaGalleryDisabledTest.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminStandaloneMediaGalleryDisabledTest.xml new file mode 100644 index 0000000000000..8b0c984c1df77 --- /dev/null +++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/AdminStandaloneMediaGalleryDisabledTest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminStandaloneMediaGalleryDisabledTest"> + <annotations> + <features value="MediaGallery"/> + <useCaseId value="https://github.com/magento/adobe-stock-integration/issues/1760"/> + <title value="Standalone Media Gallery Page should return 404 if Media Gallery is disabled"/> + <stories value="#1760 Media Gallery Page opened successfully if Enhanced Media Gallery disabled"/> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1337102/scenarios/5106786"/> + <description value="Standalone Media Gallery Page should return 404 if Media Gallery is disabled"/> + <severity value="CRITICAL"/> + <group value="media_gallery_ui_disabled"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> + <actionGroup ref="AssertAdminPageIs404ActionGroup" stepKey="see404Page"/> + </test> +</tests> diff --git a/app/code/Magento/MediaGalleryUi/Ui/Component/DirectoriesTree.php b/app/code/Magento/MediaGalleryUi/Ui/Component/DirectoryTree.php similarity index 81% rename from app/code/Magento/MediaGalleryUi/Ui/Component/DirectoriesTree.php rename to app/code/Magento/MediaGalleryUi/Ui/Component/DirectoryTree.php index 4047a4fcb98d8..269bc1f8bcba7 100644 --- a/app/code/Magento/MediaGalleryUi/Ui/Component/DirectoriesTree.php +++ b/app/code/Magento/MediaGalleryUi/Ui/Component/DirectoryTree.php @@ -14,7 +14,7 @@ /** * Directories tree component */ -class DirectoriesTree extends Container +class DirectoryTree extends Container { /** * @var UrlInterface @@ -50,9 +50,9 @@ public function prepare(): void array_replace_recursive( (array) $this->getData('config'), [ - 'getDirectoryTreeUrl' => $this->url->getUrl("media_gallery/directories/gettree"), - 'deleteDirectoryUrl' => $this->url->getUrl("media_gallery/directories/delete"), - 'createDirectoryUrl' => $this->url->getUrl("media_gallery/directories/create") + 'getDirectoryTreeUrl' => $this->url->getUrl('media_gallery/directories/gettree'), + 'deleteDirectoryUrl' => $this->url->getUrl('media_gallery/directories/delete'), + 'createDirectoryUrl' => $this->url->getUrl('media_gallery/directories/create') ] ) ); diff --git a/app/code/Magento/MediaGalleryUi/etc/di.xml b/app/code/Magento/MediaGalleryUi/etc/di.xml index a8c4e2a8d8963..6ed3a98bbf03a 100644 --- a/app/code/Magento/MediaGalleryUi/etc/di.xml +++ b/app/code/Magento/MediaGalleryUi/etc/di.xml @@ -28,11 +28,6 @@ </argument> </arguments> </type> - <type name="Magento\MediaGalleryUi\Model\Directories\GetFolderTree"> - <arguments> - <argument name="path" xsi:type="string">media</argument> - </arguments> - </type> <type name="Magento\MediaGallerySynchronizationApi\Model\ImportFilesComposite"> <plugin name="createMediaGalleryThumbnails" type="Magento\MediaGalleryUi\Plugin\CreateThumbnails"/> </type> diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/media_gallery_listing.xml b/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/media_gallery_listing.xml index 49206043725f9..66731b1cbae6f 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/media_gallery_listing.xml +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/media_gallery_listing.xml @@ -219,7 +219,7 @@ </container> </listingToolbar> <container name="media_gallery_directories" - class="Magento\MediaGalleryUi\Ui\Component\DirectoriesTree" + class="Magento\MediaGalleryUi\Ui\Component\DirectoryTree" template="Magento_MediaGalleryUi/grid/directories/directoryTree" component="Magento_MediaGalleryUi/js/directory/directoryTree"/> <columns name="media_gallery_columns" component="Magento_MediaGalleryUi/js/grid/masonry"> diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/standalone_media_gallery_listing.xml b/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/standalone_media_gallery_listing.xml index 655178c104492..3656a8ea25f74 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/standalone_media_gallery_listing.xml +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/ui_component/standalone_media_gallery_listing.xml @@ -206,7 +206,7 @@ </container> </listingToolbar> <container name="media_gallery_directories" - class="Magento\MediaGalleryUi\Ui\Component\DirectoriesTree" + class="Magento\MediaGalleryUi\Ui\Component\DirectoryTree" template="Magento_MediaGalleryUi/grid/directories/directoryTree" component="Magento_MediaGalleryUi/js/directory/directoryTree"/> <columns name="media_gallery_columns" component="Magento_MediaGalleryUi/js/grid/masonry"> diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/css/source/_module.less b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/css/source/_module.less index fc8bd49126d8e..6b3cd610f0348 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/css/source/_module.less +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/css/source/_module.less @@ -18,7 +18,7 @@ @color-media-gallery-buttons-border: #adadad; @color-media-gallery-buttons-text: #514943; @color-media-gallery-checkbox-background: #eee; - +@color-media-gallery-scrollbar-background: #fff; & when (@media-common = true) { .media-gallery-delete-image-action, @@ -170,8 +170,9 @@ height: 30px; margin: 1px; padding-left: 6px; + padding-right: 10px; padding-top: 6px; - width: 100%; + width: max-content; } .jstree-default .jstree-clicked { @@ -272,8 +273,18 @@ } .media-directory-container { + &::-webkit-scrollbar { + background-color: @color-media-gallery-scrollbar-background; + } + &::-webkit-scrollbar-thumb { + background-color: @color-masonry-grey; + } float: left; + max-width: 50%; + overflow-x: scroll; + overflow-y: hidden; padding-right: 40px; + scrollbar-color: @color-masonry-grey @color-media-gallery-scrollbar-background; } .media-gallery-image-block { diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/action/deleteImageWithDetailConfirmation.js b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/action/deleteImageWithDetailConfirmation.js index ed40674df20f0..28c021fe4728f 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/action/deleteImageWithDetailConfirmation.js +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/action/deleteImageWithDetailConfirmation.js @@ -21,25 +21,24 @@ define([ * @param {String} deleteImageUrl */ deleteImageAction: function (recordsIds, imageDetailsUrl, deleteImageUrl) { - var confirmationContent = $t('%1 Are you sure you want to delete "%2" image(s)?') + var confirmationContent = $t('%1Are you sure you want to delete "%2" image(s)?') .replace('%2', Object.keys(recordsIds).length), deferred = $.Deferred(); - getDetails(imageDetailsUrl, recordsIds) - .then(function (imageDetails) { + getDetails(imageDetailsUrl, recordsIds).then(function (images) { confirmationContent = confirmationContent.replace( '%1', - this.getRecordRelatedContentMessage(imageDetails) + this.getRecordRelatedContentMessage(images) + ' ' ); }.bind(this)).fail(function () { - confirmationContent = confirmationContent.replace('%1', ''); - }).always(function () { - deleteImages(recordsIds, deleteImageUrl, confirmationContent).then(function (status) { - deferred.resolve(status); - }).fail(function (error) { - deferred.reject(error); - }); - }); + confirmationContent = confirmationContent.replace('%1', ''); + }).always(function () { + deleteImages(recordsIds, deleteImageUrl, confirmationContent).then(function (status) { + deferred.resolve(status); + }).fail(function (error) { + deferred.reject(error); + }); + }); return deferred.promise(); }, diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directories.js b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directories.js index d7f756d8bbd90..6d8d38a1ca1d6 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directories.js +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directories.js @@ -23,6 +23,7 @@ define([ deleteButtonSelector: '#delete_folder', createFolderButtonSelector: '#create_folder', messageDelay: 5, + selectedFolder: null, messagesName: 'media_gallery_listing.media_gallery_listing.messages', modules: { directoryTree: '${ $.parentName }.media_gallery_directories', @@ -47,51 +48,57 @@ define([ */ initEvents: function () { $(this.deleteButtonSelector).on('delete_folder', function () { - this.getConfirmationPopupDeleteFolder(); + this.deleteFolder(); }.bind(this)); $(this.createFolderButtonSelector).on('create_folder', function () { - this.getPrompt({ - title: $t('New Folder Name:'), - content: '', - actions: { - /** - * Confirm action - */ - confirm: function (folderName) { - createDirectory( - this.directoryTree().createDirectoryUrl, - [this.getNewFolderPath(folderName)] - ).then(function () { - this.directoryTree().reloadJsTree().then(function () { - $(this.directoryTree().directoryTreeSelector).on('loaded.jstree', function () { - this.directoryTree().locateNode(this.getNewFolderPath(folderName)); - }.bind(this)); - }.bind(this)); + this.createFolder(); + }.bind(this)); + }, - }.bind(this)).fail(function (error) { - uiAlert({ - content: error - }); + /** + * Show confirmation popup and create folder based on user input + */ + createFolder: function () { + this.getPrompt({ + title: $t('New Folder Name:'), + content: '', + actions: { + /** + * Confirm action + */ + confirm: function (folderName) { + createDirectory( + this.directoryTree().createDirectoryUrl, + [this.getNewFolderPath(folderName)] + ).then(function () { + this.directoryTree().reloadJsTree().then(function () { + $(this.directoryTree().directoryTreeSelector).on('loaded.jstree', function () { + this.directoryTree().locateNode(this.getNewFolderPath(folderName)); + }.bind(this)); + }.bind(this)); + }.bind(this)).fail(function (error) { + uiAlert({ + content: error }); - }.bind(this) - }, - buttons: [{ - text: $t('Cancel'), - class: 'action-secondary action-dismiss', + }); + }.bind(this) + }, + buttons: [{ + text: $t('Cancel'), + class: 'action-secondary action-dismiss', - /** - * Close modal - */ - click: function () { - this.closeModal(); - } - }, { - text: $t('Confirm'), - class: 'action-primary action-accept' - }] - }); - }.bind(this)); + /** + * Close modal + */ + click: function () { + this.closeModal(); + } + }, { + text: $t('Confirm'), + class: 'action-primary action-accept' + }] + }); }, /** @@ -101,11 +108,11 @@ define([ * @returns {String} */ getNewFolderPath: function (folderName) { - var selectedFolder = _.isUndefined(this.selectedFolder()) || - _.isNull(this.selectedFolder()) ? '/' : this.selectedFolder(), - folderToCreate = selectedFolder !== '/' ? selectedFolder + '/' + folderName : folderName; + if (_.isUndefined(this.selectedFolder()) || _.isNull(this.selectedFolder())) { + return folderName; + } - return folderToCreate; + return this.selectedFolder() + '/' + folderName; }, /** @@ -136,7 +143,7 @@ define([ /** * Confirmation popup for delete folder action. */ - getConfirmationPopupDeleteFolder: function () { + deleteFolder: function () { confirm({ title: $t('Are you sure you want to delete this folder?'), modalClass: 'delete-folder-confirmation-popup', diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directoryTree.js b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directoryTree.js index decc337e1b83c..2e1e9a980cd59 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directoryTree.js +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/directory/directoryTree.js @@ -20,13 +20,15 @@ define([ filterChipsProvider: 'componentType = filters, ns = ${ $.ns }', directoryTreeSelector: '#media-gallery-directory-tree', getDirectoryTreeUrl: 'media_gallery/directories/gettree', + createDirectoryUrl: 'media_gallery/directories/create', + deleteDirectoryUrl: 'media_gallery/directories/delete', jsTreeReloaded: null, modules: { directories: '${ $.name }_directories', filterChips: '${ $.filterChipsProvider }' }, listens: { - '${ $.provider }:params.filters.path': 'clearFiltersHandle' + '${ $.provider }:params.filters.path': 'updateSelectedDirectory' }, viewConfig: [{ component: 'Magento_MediaGalleryUi/js/directory/directories', @@ -49,7 +51,8 @@ define([ this.renderDirectoryTree().then(function () { this.initEvents(); }.bind(this)); - }.bind(this)); + }.bind(this) + ); return this; }, @@ -58,7 +61,6 @@ define([ * Render directory tree component. */ renderDirectoryTree: function () { - return this.getJsonTree().then(function (data) { this.createFolderIfNotExists(data).then(function (isFolderCreated) { if (isFolderCreated) { @@ -87,37 +89,37 @@ define([ * @param {Array} directories */ createFolderIfNotExists: function (directories) { - var isMediaBrowser = !_.isUndefined(window.MediabrowserUtility), - currentTreePath = isMediaBrowser ? window.MediabrowserUtility.pathId : null, + var requestedDirectory = this.getRequestedDirectory(), deferred = $.Deferred(), - decodedPath, pathArray; - if (currentTreePath) { - decodedPath = Base64.idDecode(currentTreePath); - - if (!this.isDirectoryExist(directories[0], decodedPath)) { - pathArray = this.convertPathToPathsArray(decodedPath); + if (_.isNull(requestedDirectory)) { + deferred.resolve(false); - $.each(pathArray, function (i, val) { - if (this.isDirectoryExist(directories[0], val)) { - pathArray.splice(i, 1); - } - }.bind(this)); + return deferred.promise(); + } - createDirectory( - this.createDirectoryUrl, - pathArray - ).then(function () { - deferred.resolve(true); - }); - } else { - deferred.resolve(false); - } - } else { + if (this.isDirectoryExist(directories[0], requestedDirectory)) { deferred.resolve(false); + + return deferred.promise(); } + pathArray = this.convertPathToPathsArray(requestedDirectory); + + $.each(pathArray, function (i, val) { + if (this.isDirectoryExist(directories[0], val)) { + pathArray.splice(i, 1); + } + }.bind(this)); + + createDirectory( + this.createDirectoryUrl, + pathArray + ).then(function () { + deferred.resolve(true); + }); + return deferred.promise(); }, @@ -199,7 +201,7 @@ define([ /** * Remove ability to multiple select on nodes */ - overrideMultiselectBehavior: function () { + disableMultiselectBehavior: function () { $.jstree.defaults.ui['select_range_modifier'] = false; $.jstree.defaults.ui['select_multiple_modifier'] = false; }, @@ -208,8 +210,8 @@ define([ * Handle jstree events */ initEvents: function () { - this.firejsTreeEvents(); - this.overrideMultiselectBehavior(); + this.initJsTreeEvents(); + this.disableMultiselectBehavior(); $(window).on('reload.MediaGallery', function () { this.getJsonTree().then(function (data) { @@ -217,10 +219,10 @@ define([ if (isCreated) { this.renderDirectoryTree().then(function () { this.setJsTreeReloaded(true); - this.firejsTreeEvents(); + this.initJsTreeEvents(); }.bind(this)); } else { - this.checkChipFiltersState(); + this.updateSelectedDirectory(); } }.bind(this)); }.bind(this)); @@ -230,30 +232,33 @@ define([ /** * Fire event for jstree component */ - firejsTreeEvents: function () { + initJsTreeEvents: function () { $(this.directoryTreeSelector).on('select_node.jstree', function (element, data) { - var path = $(data.rslt.obj).data('path'); - - this.setActiveNodeFilter(path); + this.setActiveNodeFilter($(data.rslt.obj).data('path')); this.setJsTreeReloaded(false); }.bind(this)); $(this.directoryTreeSelector).on('loaded.jstree', function () { - this.checkChipFiltersState(); + this.updateSelectedDirectory(); }.bind(this)); - }, /** * Verify directory filter on init event, select folder per directory filter state */ - checkChipFiltersState: function () { + updateSelectedDirectory: function () { var currentFilterPath = this.filterChips().filters.path, - isMediaBrowser = !_.isUndefined(window.MediabrowserUtility), + requestedDirectory = this.getRequestedDirectory(), currentTreePath; - currentTreePath = this.isFiltersApplied(currentFilterPath) || !isMediaBrowser ? currentFilterPath : - Base64.idDecode(window.MediabrowserUtility.pathId); + if (_.isUndefined(currentFilterPath)) { + this.clearFiltersHandle(); + + return; + } + + currentTreePath = this.isFilterApplied(currentFilterPath) || _.isNull(requestedDirectory) ? + currentFilterPath : requestedDirectory; if (this.folderExistsInTree(currentTreePath)) { this.locateNode(currentTreePath); @@ -275,14 +280,23 @@ define([ return false; }, + /** + * Get requested directory from MediabrowserUtility + * + * @returns {String|null} + */ + getRequestedDirectory: function () { + return !_.isUndefined(window.MediabrowserUtility) && window.MediabrowserUtility.pathId !== '' ? + Base64.idDecode(window.MediabrowserUtility.pathId) : null; + }, + /** * Check if need to select directory by filters state * * @param {String} currentFilterPath */ - isFiltersApplied: function (currentFilterPath) { - return !_.isUndefined(currentFilterPath) && currentFilterPath !== '' && - currentFilterPath !== 'wysiwyg' && currentFilterPath !== 'catalog/category'; + isFilterApplied: function (currentFilterPath) { + return !_.isUndefined(currentFilterPath) && currentFilterPath !== ''; }, /** @@ -291,9 +305,7 @@ define([ * @param {String} path */ locateNode: function (path) { - var selectedId = $(this.directoryTreeSelector).jstree('get_selected').attr('id'); - - if (path === selectedId) { + if (path === $(this.directoryTreeSelector).jstree('get_selected').attr('id')) { return; } path = path.replace(/\//g, '\\/'); @@ -303,14 +315,12 @@ define([ }, /** - * Listener to clear filters event + * Clear filters */ clearFiltersHandle: function () { - if (_.isUndefined(this.filterChips().filters.path)) { - $(this.directoryTreeSelector).jstree('deselect_all'); - this.activeNode(null); - this.directories().setInActive(); - } + $(this.directoryTreeSelector).jstree('deselect_all'); + this.activeNode(null); + this.directories().setInActive(); }, /** @@ -319,7 +329,6 @@ define([ * @param {String} nodePath */ setActiveNodeFilter: function (nodePath) { - if (this.activeNode() === nodePath && !this.jsTreeReloaded) { this.selectStorageRoot(); } else { @@ -341,14 +350,13 @@ define([ this.filterChips().set('applied', filters); this.activeNode(null); this.waitForCondition( - function () { - return _.isUndefined(this.directories()); - }.bind(this), function () { - this.directories().setInActive(); - }.bind(this) - ); - + return _.isUndefined(this.directories()); + }.bind(this), + function () { + this.directories().setInActive(); + }.bind(this) + ); }, /** @@ -372,8 +380,8 @@ define([ }, /** - * Remove active node from directory tree, and select next - */ + * Remove active node from directory tree, and select next + */ removeNode: function () { $(this.directoryTreeSelector).jstree('remove'); }, @@ -390,7 +398,6 @@ define([ filters = $.extend(true, filters, applied); filters.path = path; this.filterChips().set('applied', filters); - }, /** diff --git a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/grid/massaction/massactions.js b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/grid/massaction/massactions.js index 4f09854005f23..03e82e65b5db5 100644 --- a/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/grid/massaction/massactions.js +++ b/app/code/Magento/MediaGalleryUi/view/adminhtml/web/js/grid/massaction/massactions.js @@ -141,10 +141,8 @@ define([ if (response.status === 'canceled') { return; } - this.imageModel().selected({}); - this.massActionMode(false); - this.switchMode(); - }.bind(this)); + $(window).trigger('terminateMassAction.MediaGallery'); + }); } }.bind(this)); } diff --git a/app/code/Magento/MessageQueue/etc/di.xml b/app/code/Magento/MessageQueue/etc/di.xml index f60eb5fbc20df..b283280dc4580 100644 --- a/app/code/Magento/MessageQueue/etc/di.xml +++ b/app/code/Magento/MessageQueue/etc/di.xml @@ -6,7 +6,6 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <preference for="Magento\Framework\MessageQueue\ConfigInterface" type="Magento\Framework\MessageQueue\Config\Proxy" /> <preference for="Magento\Framework\MessageQueue\LockInterface" type="Magento\Framework\MessageQueue\Lock" /> <preference for="Magento\Framework\MessageQueue\Lock\WriterInterface" type="Magento\MessageQueue\Model\ResourceModel\Lock" /> <preference for="Magento\Framework\MessageQueue\Lock\ReaderInterface" type="Magento\MessageQueue\Model\ResourceModel\Lock" /> diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index 49212202b5f62..8845395be406e 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -695,7 +695,7 @@ protected function _prepareOrder(\Magento\Quote\Model\Quote\Address $address) ); $shippingMethodCode = $address->getShippingMethod(); - if (isset($shippingMethodCode) && !empty($shippingMethodCode)) { + if ($shippingMethodCode) { $rate = $address->getShippingRateByCode($shippingMethodCode); $shippingPrice = $rate->getPrice(); } else { @@ -975,7 +975,8 @@ public function getMinimumAmountError() \Magento\Store\Model\ScopeInterface::SCOPE_STORE ); } - return $error; + + return __($error); } /** diff --git a/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontRemoveProductOnCheckoutActionGroup.xml b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontRemoveProductOnCheckoutActionGroup.xml new file mode 100644 index 0000000000000..af0f3e2d597b8 --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontRemoveProductOnCheckoutActionGroup.xml @@ -0,0 +1,18 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontRemoveProductOnCheckoutActionGroup"> + <arguments> + <argument name="itemNumber" type="string" defaultValue="1"/> + </arguments> + + <click selector="{{MultishippingSection.removeItemButton(itemNumber)}}" stepKey="removeItem"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection/MultishippingSection.xml b/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection/MultishippingSection.xml index db037d50f7dc6..9c89ffa3cd405 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection/MultishippingSection.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection/MultishippingSection.xml @@ -14,5 +14,6 @@ <element name="shippingAddressSelector" type="select" selector="//tr[position()={{addressPosition}}]//td[@data-th='Send To']//select" parameterized="true"/> <element name="shippingAddressOptions" type="select" selector="#multiship-addresses-table tbody tr:nth-of-type({{addressPosition}}) .col.address select option:nth-of-type({{optionIndex}})" parameterized="true"/> <element name="selectShippingAddress" type="select" selector="(//table[@id='multiship-addresses-table'] //div[@class='field address'] //select)[{{sequenceNumber}}]" parameterized="true"/> + <element name="removeItemButton" type="button" selector="//a[contains(@title, 'Remove Item')][{{var}}]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithWithVirtualProductTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithWithVirtualProductTest.xml new file mode 100644 index 0000000000000..632950120474d --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithWithVirtualProductTest.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCheckoutWithWithVirtualProductTest"> + <annotations> + <features value="Multishipping"/> + <stories value="Multiple Shipping"/> + <title value="Check error when cart contains virtual product"/> + <description value="Check error when cart contains only virtual product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-36921"/> + <group value="Multishipment"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="firstProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="VirtualProduct" stepKey="virtualProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Customer_US_UK_DE" stepKey="createCustomerWithMultipleAddresses"/> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + <deleteData createDataKey="firstProduct" stepKey="deleteFirstProduct"/> + <deleteData createDataKey="virtualProduct" stepKey="deleteVirtualProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomerWithMultipleAddresses" stepKey="deleteCustomer"/> + </after> + <!-- Login to the Storefront as created customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginAsCustomer"> + <argument name="Customer" value="$$createCustomerWithMultipleAddresses$$"/> + </actionGroup> + <!-- Open the simple product page --> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="goToFirstProductPage"> + <argument name="productUrl" value="$$firstProduct.custom_attributes[url_key]$$"/> + </actionGroup> + <!-- Add the simple product to the Shopping Cart --> + <actionGroup ref="AddProductWithQtyToCartFromStorefrontProductPageActionGroup" stepKey="addFirstProductToCart"> + <argument name="productName" value="$$firstProduct.name$$"/> + <argument name="productQty" value="1"/> + </actionGroup> + <!-- Open the virtual product page --> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="goToVirtualProductPage"> + <argument name="productUrl" value="$$virtualProduct.custom_attributes[url_key]$$"/> + </actionGroup> + <!-- Add the virtual product to the Shopping Cart --> + <actionGroup ref="AddProductWithQtyToCartFromStorefrontProductPageActionGroup" stepKey="addVirtualProductToCart"> + <argument name="productName" value="$$virtualProduct.name$$"/> + <argument name="productQty" value="1"/> + </actionGroup> + <!-- Go to Cart --> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="openCart"/> + <!-- Check Out with Multiple Addresses --> + <actionGroup ref="StorefrontCheckoutWithMultipleAddressesActionGroup" stepKey="checkoutWithMultipleAddresses"/> + <!-- Remove simple product from cart --> + <actionGroup ref="StorefrontRemoveProductOnCheckoutActionGroup" stepKey="removeFirstProductFromCart"/> + <!-- Assert error message on checkout --> + <actionGroup ref="StorefrontAssertCheckoutErrorMessageActionGroup" stepKey="assertErrorMessage"> + <argument name="message" value="The current cart does not match multi shipping criteria, please review or contact the store administrator"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Multishipping/etc/config.xml b/app/code/Magento/Multishipping/etc/config.xml index aee4199ed4757..0df8742016aed 100644 --- a/app/code/Magento/Multishipping/etc/config.xml +++ b/app/code/Magento/Multishipping/etc/config.xml @@ -13,5 +13,10 @@ <checkout_multiple_maximum_qty>100</checkout_multiple_maximum_qty> </options> </multishipping> + <sales> + <minimum_order> + <multi_address_error_message>The current cart does not match multi shipping criteria, please review or contact the store administrator</multi_address_error_message> + </minimum_order> + </sales> </default> </config> diff --git a/app/code/Magento/Multishipping/i18n/en_US.csv b/app/code/Magento/Multishipping/i18n/en_US.csv index 0c248bdcc1af3..430b16b8cc237 100644 --- a/app/code/Magento/Multishipping/i18n/en_US.csv +++ b/app/code/Magento/Multishipping/i18n/en_US.csv @@ -92,3 +92,4 @@ Options,Options "Error:","Error:" "We are unable to process your request. Please, try again later.","We are unable to process your request. Please, try again later." "Quote address for failed order ID "%1" not found.","Quote address for failed order ID "%1" not found." +"The current cart does not match multi shipping criteria, please review or contact the store administrator","The current cart does not match multi shipping criteria, please review or contact the store administrator" diff --git a/app/code/Magento/Newsletter/Model/SubscriptionManager.php b/app/code/Magento/Newsletter/Model/SubscriptionManager.php index 846d095625e0c..57c6cd8b843a7 100644 --- a/app/code/Magento/Newsletter/Model/SubscriptionManager.php +++ b/app/code/Magento/Newsletter/Model/SubscriptionManager.php @@ -195,12 +195,14 @@ private function saveSubscriber( ): bool { $statusChanged = (int)$subscriber->getStatus() !== $status; $emailChanged = $subscriber->getEmail() !== $customer->getEmail(); - if ($subscriber->getId() - && !$statusChanged - && (int)$subscriber->getCustomerId() === (int)$customer->getId() - && (int)$subscriber->getStoreId() === $storeId - && !$emailChanged - ) { + if ($this->dontNeedToSaveSubscriber( + $subscriber, + $customer, + $statusChanged, + $storeId, + $status, + $emailChanged + )) { return false; } @@ -220,10 +222,37 @@ private function saveSubscriber( /** * If the subscriber is waiting to confirm from the customer - * and customer changed the email + * or customer changed the email * than need to send confirmation letter to the new email */ - return $status === Subscriber::STATUS_NOT_ACTIVE && $emailChanged; + return $status === Subscriber::STATUS_NOT_ACTIVE || $emailChanged; + } + + /** + * Don't need to save subscriber model + * + * @param Subscriber $subscriber + * @param CustomerInterface $customer + * @param bool $statusChanged + * @param int $storeId + * @param int $status + * @param bool $emailChanged + * @return bool + */ + private function dontNeedToSaveSubscriber( + Subscriber $subscriber, + CustomerInterface $customer, + bool $statusChanged, + int $storeId, + int $status, + bool $emailChanged + ): bool { + return $subscriber->getId() + && !$statusChanged + && (int)$subscriber->getCustomerId() === (int)$customer->getId() + && (int)$subscriber->getStoreId() === $storeId + && !$emailChanged + && $status !== Subscriber::STATUS_NOT_ACTIVE; } /** diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/SubscriptionManagerTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/SubscriptionManagerTest.php index 4e1f18a26a95a..6139d86191f44 100644 --- a/app/code/Magento/Newsletter/Test/Unit/Model/SubscriptionManagerTest.php +++ b/app/code/Magento/Newsletter/Test/Unit/Model/SubscriptionManagerTest.php @@ -454,7 +454,7 @@ public function subscribeCustomerDataProvider(): array 'subscriber_status' => Subscriber::STATUS_SUBSCRIBED, 'subscriber_confirm_code' => '', ], - 'needToSendEmail' => false, + 'needToSendEmail' => true, ], 'Update subscription data: subscription confirm required ' => [ 'subscriber_data' => [ @@ -618,7 +618,7 @@ public function unsubscribeCustomerDataProvider(): array 'subscriber_status' => Subscriber::STATUS_NOT_ACTIVE, 'subscriber_confirm_code' => '', ], - 'needToSendEmail' => false, + 'needToSendEmail' => true, ], 'Update subscription data' => [ 'subscriber_data' => [ @@ -642,7 +642,7 @@ public function unsubscribeCustomerDataProvider(): array 'subscriber_status' => Subscriber::STATUS_UNSUBSCRIBED, 'subscriber_confirm_code' => '', ], - 'needToSendEmail' => false, + 'needToSendEmail' => true, ], ]; } diff --git a/app/code/Magento/PageCache/Plugin/AppendNoStoreCacheHeader.php b/app/code/Magento/PageCache/Plugin/AppendNoStoreCacheHeader.php new file mode 100644 index 0000000000000..fc18855a51710 --- /dev/null +++ b/app/code/Magento/PageCache/Plugin/AppendNoStoreCacheHeader.php @@ -0,0 +1,30 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\PageCache\Plugin; + +use Magento\Framework\App\FrontControllerInterface; +use Magento\Framework\App\Response\HttpInterface; + +class AppendNoStoreCacheHeader +{ + /** + * Set cache-control header + * + * @param FrontControllerInterface $controller + * @param HttpInterface $response + * @return HttpInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterDispatch(FrontControllerInterface $controller, HttpInterface $response): HttpInterface + { + $response->setHeader('Cache-Control', 'no-store'); + return $response; + } +} diff --git a/app/code/Magento/PageCache/etc/webapi_rest/di.xml b/app/code/Magento/PageCache/etc/webapi_rest/di.xml new file mode 100644 index 0000000000000..04906a615a9df --- /dev/null +++ b/app/code/Magento/PageCache/etc/webapi_rest/di.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Framework\App\FrontControllerInterface"> + <plugin name="append_no_store_cache_header" type="Magento\PageCache\Plugin\AppendNoStoreCacheHeader" /> + </type> +</config> diff --git a/app/code/Magento/PageCache/etc/webapi_soap/di.xml b/app/code/Magento/PageCache/etc/webapi_soap/di.xml new file mode 100644 index 0000000000000..04906a615a9df --- /dev/null +++ b/app/code/Magento/PageCache/etc/webapi_soap/di.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Framework\App\FrontControllerInterface"> + <plugin name="append_no_store_cache_header" type="Magento\PageCache\Plugin\AppendNoStoreCacheHeader" /> + </type> +</config> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AddConfigurableProductToOrderFromShoppingCartTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AddConfigurableProductToOrderFromShoppingCartTest.xml index 6f4073bf70f46..127fd1dd4e006 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AddConfigurableProductToOrderFromShoppingCartTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AddConfigurableProductToOrderFromShoppingCartTest.xml @@ -97,8 +97,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCreatedCustomer"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEditButton"/> - <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickEditButton"/> <!-- Click create order --> <click selector="{{AdminCustomerMainActionsSection.createOrderBtn}}" stepKey="clickCreateOrder"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml index d8a9effa56dac..701b7ebe4a958 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml @@ -58,8 +58,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCreatedCustomer"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEditButton"/> - <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickEditButton"/> <!-- Click create order --> <click selector="{{AdminCustomerMainActionsSection.createOrderBtn}}" stepKey="clickCreateOrder"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedConfigurableProductOnOrderPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedConfigurableProductOnOrderPageTest.xml index c635e6b0ad6b2..8e9e117d2d995 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedConfigurableProductOnOrderPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedConfigurableProductOnOrderPageTest.xml @@ -96,8 +96,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCreatedCustomer"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEditButton"/> - <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickEditButton"/> <!-- Click create order --> <click selector="{{AdminCustomerMainActionsSection.createOrderBtn}}" stepKey="clickCreateOrder"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedSimpleProductOnOrderPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedSimpleProductOnOrderPageTest.xml index eb28ebfd068da..71da699e533bc 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedSimpleProductOnOrderPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/MoveLastOrderedSimpleProductOnOrderPageTest.xml @@ -46,8 +46,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCreatedCustomer"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEditButton"/> - <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickEditButton"/> <!-- Click create order --> <click selector="{{AdminCustomerMainActionsSection.createOrderBtn}}" stepKey="clickCreateOrder"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedBundleFixedProductOnOrderPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedBundleFixedProductOnOrderPageTest.xml index c3fc7a4952143..452d65ea5ae57 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedBundleFixedProductOnOrderPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedBundleFixedProductOnOrderPageTest.xml @@ -96,8 +96,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCreatedCustomer"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEditButton"/> - <waitForPageLoad stepKey="waitForCustomerPageLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickEditButton"/> <!-- Click create order --> <click selector="{{AdminCustomerMainActionsSection.createOrderBtn}}" stepKey="clickCreateOrder"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedConfigurableProductOnOrderPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedConfigurableProductOnOrderPageTest.xml index 0e021600ab3e3..4d1ebddc7c2b3 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedConfigurableProductOnOrderPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/MoveRecentlyViewedConfigurableProductOnOrderPageTest.xml @@ -99,8 +99,7 @@ <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterCreatedCustomer"> <argument name="email" value="$$createCustomer.email$$"/> </actionGroup> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEditButton"/> - <waitForPageLoad stepKey="waitForCustomerPageLoad"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickEditButton"/> <!-- Click create order --> <click selector="{{AdminCustomerMainActionsSection.createOrderBtn}}" stepKey="clickCreateOrder"/> diff --git a/app/code/Magento/Store/Block/Switcher.php b/app/code/Magento/Store/Block/Switcher.php index f15349f11066d..a924805fcba90 100644 --- a/app/code/Magento/Store/Block/Switcher.php +++ b/app/code/Magento/Store/Block/Switcher.php @@ -170,9 +170,15 @@ public function getGroups() if ($store) { $group->setHomeUrl($store->getHomeUrl()); + $group->setSortOrder($store->getSortOrder()); $groups[] = $group; } } + + usort($groups, static function ($itemA, $itemB) { + return (int)$itemA->getSortOrder() <=> (int)$itemB->getSortOrder(); + }); + $this->setData('groups', $groups); } return $this->getData('groups'); @@ -193,7 +199,12 @@ public function getStores() $stores = []; } else { $stores = $rawStores[$groupId]; + + uasort($stores, static function ($itemA, $itemB) { + return (int)$itemA->getSortOrder() <=> (int)$itemB->getSortOrder(); + }); } + $this->setData('stores', $stores); } return $this->getData('stores'); diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCheckStoreViewOptionsActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCheckStoreViewOptionsActionGroup.xml new file mode 100644 index 0000000000000..ba96633a621c2 --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCheckStoreViewOptionsActionGroup.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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCheckStoreViewOptionsActionGroup"> + <annotations> + <description>Goes to the Catalog->Product filters and check store view options at the Store View dropdown</description> + </annotations> + <arguments> + <argument name="storeViewId" type="string"/> + </arguments> + <amOnPage url="{{ProductCatalogPage.url}}" stepKey="OpenProductCatalogPage"/> + <waitForPageLoad stepKey="waitForProductCatalogPage"/> + <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="clickFiltersButton"/> + <click selector="{{AdminProductFiltersSection.storeViewDropDown}}" stepKey="clickStoreViewSwitchDropdown"/> + <waitForElementVisible selector="{{AdminProductFiltersSection.storeViewDropDown}}" stepKey="waitForWebsiteAreVisible"/> + <seeElement selector="{{AdminProductGridFilterSection.storeViewOptions(storeViewId)}}" stepKey="seeStoreViewOption"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewFillSortOrderActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewFillSortOrderActionGroup.xml new file mode 100644 index 0000000000000..1b9b147209c66 --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewFillSortOrderActionGroup.xml @@ -0,0 +1,21 @@ +<?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="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateStoreViewFillSortOrderActionGroup" extends="AdminCreateStoreViewActionGroup"> + <annotations> + <description>Fill 'Sort Order' field</description> + </annotations> + <arguments> + <argument name="sortOrder" type="string" defaultValue="0"/> + </arguments> + + <fillField selector="{{AdminNewStoreSection.sortOrderTextField}}" userInput="{{sortOrder}}" stepKey="fillSortOrder" after="enterStoreViewCode"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml index bdb1842cf2959..39664ae10a07d 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml @@ -206,4 +206,23 @@ <data key="store_type">store</data> <data key="store_action">add</data> </entity> + <!--Stores views with same name--> + <entity name="customStoreViewSameNameFirst" type="store"> + <data key="name">sameNameStoreView</data> + <data key="code" unique="suffix">storeViewCode</data> + <data key="is_active">1</data> + <data key="store_id">null</data> + <data key="store_action">add</data> + <data key="store_type">store</data> + <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> + </entity> + <entity name="customStoreViewSameNameSecond" type="store"> + <data key="name">sameNameStoreView</data> + <data key="code" unique="suffix">storeViewCode</data> + <data key="is_active">1</data> + <data key="store_id">null</data> + <data key="store_action">add</data> + <data key="store_type">store</data> + <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> + </entity> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection/AdminStoresGridSection.xml b/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection/AdminStoresGridSection.xml index e56836c491276..cd7f180d0bb0e 100644 --- a/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection/AdminStoresGridSection.xml +++ b/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection/AdminStoresGridSection.xml @@ -22,5 +22,6 @@ <element name="emptyText" type="text" selector="//tr[@class='data-grid-tr-no-data even']/td[@class='empty-text']"/> <element name="websiteName" type="text" selector="//td[@class='a-left col-website_title ']/a[contains(.,'{{websiteName}}')]" parameterized="true"/> <element name="gridCell" type="text" selector="//table[@class='data-grid']//tr[{{row}}]//td[count(//table[@class='data-grid']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> + <element name="storeViewLinkInNthRow" type="text" selector="tr:nth-of-type({{row}}) > .col-store_title > a" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Store/Test/Mftf/Test/AdminCreateDuplicateNameStoreViewTest.xml b/app/code/Magento/Store/Test/Mftf/Test/AdminCreateDuplicateNameStoreViewTest.xml new file mode 100644 index 0000000000000..ec81424b1acfa --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/Test/AdminCreateDuplicateNameStoreViewTest.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateDuplicateNameStoreViewTest"> + <annotations> + <features value="Store"/> + <stories value="Create a store view in admin"/> + <title value="Admin should be able to create a Store View with the same name"/> + <description value="Admin should be able to create a Store View with the same name"/> + <group value="storeView"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-36863"/> + </annotations> + <before> + <!--Create two store views with same name, but different codes--> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createFirstStoreView"> + <argument name="StoreGroup" value="_defaultStoreGroup"/> + <argument name="customStore" value="customStoreViewSameNameFirst"/> + </actionGroup> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createSecondStoreView"> + <argument name="StoreGroup" value="_defaultStoreGroup"/> + <argument name="customStore" value="customStoreViewSameNameSecond"/> + </actionGroup> + </before> + <after> + <!--Delete both store views--> + <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteFirstStoreView"> + <argument name="customStore" value="customStoreViewSameNameFirst"/> + </actionGroup> + <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteSecondStoreView"> + <argument name="customStore" value="customStoreViewSameNameSecond"/> + </actionGroup> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <!--Get Id of store views--> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="navigateToStoreViews"/> + <click selector="{{AdminStoresGridSection.storeViewLinkInNthRow('2')}}" stepKey="openFirstViewPAge" /> + <grabFromCurrentUrl stepKey="getStoreViewIdFirst" regex="~/store_id/(\d+)/~"/> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="navigateToStoreViewsAgain"/> + <click selector="{{AdminStoresGridSection.storeViewLinkInNthRow('3')}}" stepKey="openSecondViewPAge" /> + <grabFromCurrentUrl stepKey="getStoreViewIdSecond" regex="~/store_id/(\d+)/~"/> + <!--Go to catalog -> product grid, open the filter and check the listed store view--> + <actionGroup ref="AdminCheckStoreViewOptionsActionGroup" stepKey="checkFirstStoreView"> + <argument name="storeViewId" value="{$getStoreViewIdFirst}"/> + </actionGroup> + <actionGroup ref="AdminCheckStoreViewOptionsActionGroup" stepKey="checkSecondStoreView"> + <argument name="storeViewId" value="{$getStoreViewIdSecond}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Store/Test/Mftf/Test/StorefrontCheckSortOrderStoreViewTest.xml b/app/code/Magento/Store/Test/Mftf/Test/StorefrontCheckSortOrderStoreViewTest.xml new file mode 100644 index 0000000000000..442ee99e12793 --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/Test/StorefrontCheckSortOrderStoreViewTest.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCheckSortOrderStoreView"> + <annotations> + <features value="Backend"/> + <stories value="Github issue: #13401 'Store View' sort order values are not reflected"/> + <title value="Check 'Store view' sort order values"/> + <description value="Check 'Store View' sort order values no frontend store-switcher"/> + <severity value="MINOR"/> + <group value="store"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createFirstStore"> + <argument name="website" value="{{_defaultWebsite.name}}"/> + <argument name="storeGroupName" value="{{customStoreGroup.name}}"/> + <argument name="storeGroupCode" value="{{customStoreGroup.code}}"/> + </actionGroup> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createSecondStore"> + <argument name="website" value="{{_defaultWebsite.name}}"/> + <argument name="storeGroupName" value="{{SecondStoreGroupUnique.name}}"/> + <argument name="storeGroupCode" value="{{SecondStoreGroupUnique.code}}"/> + </actionGroup> + </before> + <after> + <actionGroup ref="DeleteCustomStoreActionGroup" stepKey="deleteCustomStore"> + <argument name="storeGroupName" value="customStoreGroup.name"/> + </actionGroup> + <actionGroup ref="DeleteCustomStoreActionGroup" stepKey="deleteSecondStore"> + <argument name="storeGroupName" value="SecondStoreGroupUnique.name"/> + </actionGroup> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> + <argument name="indices" value=""/> + </actionGroup> + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> + <argument name="tags" value=""/> + </actionGroup> + </after> + <actionGroup ref="AdminCreateStoreViewFillSortOrderActionGroup" stepKey="createFirstStoreView"> + <argument name="StoreGroup" value="customStoreGroup"/> + <argument name="customStore" value="customStoreGroup"/> + <argument name="sortOrder" value="30"/> + </actionGroup> + <actionGroup ref="AdminCreateStoreViewFillSortOrderActionGroup" stepKey="createSecondStoreView"> + <argument name="StoreGroup" value="SecondStoreGroupUnique"/> + <argument name="customStore" value="SecondStoreGroupUnique"/> + <argument name="sortOrder" value="20"/> + </actionGroup> + + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomePage"/> + <click stepKey="selectStoreSwitcher" selector="{{StorefrontFooterSection.switchStoreButton}}"/> + <grabTextFrom selector="{{StorefrontFooterSection.storeViewOptionNumber('1')}}" stepKey="grabSwatchFirstOption"/> + <grabTextFrom selector="{{StorefrontFooterSection.storeViewOptionNumber('2')}}" stepKey="grabSwatchSecondOption"/> + <assertStringContainsString stepKey="checkingSwatchFirstOption"> + <expectedResult type="string">{{SecondStoreGroupUnique.name}}</expectedResult> + <actualResult type="variable">$grabSwatchFirstOption</actualResult> + </assertStringContainsString> + <assertStringContainsString stepKey="checkingSwatchSecondOption"> + <expectedResult type="string">{{customStoreGroup.name}}</expectedResult> + <actualResult type="variable">$grabSwatchSecondOption</actualResult> + </assertStringContainsString> + </test> +</tests> diff --git a/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php b/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php index 9106da8ffb177..60c69834f6aa6 100644 --- a/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php +++ b/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php @@ -7,91 +7,159 @@ namespace Magento\Store\Test\Unit\Block; +use Magento\Directory\Helper\Data; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Data\Helper\PostHelper; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\UrlInterface; use Magento\Framework\View\Element\Template\Context; use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Block\Switcher; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; +use Magento\Store\Model\Website; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class SwitcherTest extends TestCase { - /** @var Switcher */ - protected $switcher; - - /** @var Context|MockObject */ - protected $context; + /** + * @var Switcher + */ + private $switcher; - /** @var PostHelper|MockObject */ - protected $corePostDataHelper; + /** + * @var PostHelper|MockObject + */ + private $corePostDataHelperMock; - /** @var StoreManagerInterface|MockObject */ - protected $storeManager; + /** + * @var StoreManagerInterface|MockObject + */ + private $storeManagerMock; - /** @var UrlInterface|MockObject */ - protected $urlBuilder; + /** + * @var UrlInterface|MockObject + */ + private $urlBuilderMock; - /** @var StoreInterface|MockObject */ - private $store; + /** + * @var ScopeConfigInterface|MockObject + */ + private $scopeConfigMock; /** * @return void */ protected function setUp(): void { - $this->storeManager = $this->getMockBuilder(StoreManagerInterface::class) - ->getMock(); - $this->urlBuilder = $this->getMockForAbstractClass(UrlInterface::class); - $this->context = $this->createMock(Context::class); - $this->context->expects($this->any())->method('getStoreManager')->willReturn($this->storeManager); - $this->context->expects($this->any())->method('getUrlBuilder')->willReturn($this->urlBuilder); - $this->corePostDataHelper = $this->createMock(PostHelper::class); - $this->store = $this->getMockBuilder(StoreInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)->getMock(); + $this->urlBuilderMock = $this->createMock(UrlInterface::class); + $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); + $contextMock = $this->createMock(Context::class); + $contextMock->method('getStoreManager')->willReturn($this->storeManagerMock); + $contextMock->method('getUrlBuilder')->willReturn($this->urlBuilderMock); + $contextMock->method('getScopeConfig')->willReturn($this->scopeConfigMock); + $this->corePostDataHelperMock = $this->createMock(PostHelper::class); $this->switcher = (new ObjectManager($this))->getObject( Switcher::class, [ - 'context' => $this->context, - 'postDataHelper' => $this->corePostDataHelper, + 'context' => $contextMock, + 'postDataHelper' => $this->corePostDataHelperMock, ] ); } + public function testGetStoresSortOrder() + { + $groupId = 1; + $storesSortOrder = [ + 1 => 2, + 2 => 4, + 3 => 1, + 4 => 3 + ]; + + $currentStoreMock = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $currentStoreMock->method('getGroupId')->willReturn($groupId); + $currentStoreMock->method('isUseStoreInUrl')->willReturn(false); + $this->storeManagerMock->method('getStore') + ->willReturn($currentStoreMock); + + $currentWebsiteMock = $this->getMockBuilder(Website::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManagerMock->method('getWebsite') + ->willReturn($currentWebsiteMock); + + $stores = []; + foreach ($storesSortOrder as $storeId => $sortOrder) { + $storeMock = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->setMethods(['getId', 'getGroupId', 'getSortOrder', 'isActive', 'getUrl']) + ->getMock(); + $storeMock->method('getId')->willReturn($storeId); + $storeMock->method('getGroupId')->willReturn($groupId); + $storeMock->method('getSortOrder')->willReturn($sortOrder); + $storeMock->method('isActive')->willReturn(true); + $storeMock->method('getUrl')->willReturn('https://example.org'); + $stores[] = $storeMock; + } + + $scopeConfigMap = array_map(static function ($item) { + return [ + Data::XML_PATH_DEFAULT_LOCALE, + ScopeInterface::SCOPE_STORE, + $item, + 'en_US' + ]; + }, $stores); + $this->scopeConfigMock->method('getValue') + ->willReturnMap($scopeConfigMap); + + $currentWebsiteMock->method('getStores') + ->willReturn($stores); + + $this->assertEquals([3, 1, 4, 2], array_keys($this->switcher->getStores())); + } + /** * @return void */ public function testGetTargetStorePostData() { - $store = $this->getMockBuilder(Store::class) + $storeMock = $this->getMockBuilder(Store::class) ->disableOriginalConstructor() ->getMock(); - $store->expects($this->any()) - ->method('getCode') + $oldStoreMock = $this->getMockBuilder(StoreInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $storeMock->method('getCode') ->willReturn('new-store'); $storeSwitchUrl = 'http://domain.com/stores/store/redirect'; - $store->expects($this->atLeastOnce()) + $storeMock->expects($this->atLeastOnce()) ->method('getCurrentUrl') ->with(false) ->willReturn($storeSwitchUrl); - $this->storeManager->expects($this->once()) + $this->storeManagerMock->expects($this->once()) ->method('getStore') - ->willReturn($this->store); - $this->store->expects($this->once()) + ->willReturn($oldStoreMock); + $oldStoreMock->expects($this->once()) ->method('getCode') ->willReturn('old-store'); - $this->urlBuilder->expects($this->once()) + $this->urlBuilderMock->expects($this->once()) ->method('getUrl') ->willReturn($storeSwitchUrl); - $this->corePostDataHelper->expects($this->any()) - ->method('getPostData') + $this->corePostDataHelperMock->method('getPostData') ->with($storeSwitchUrl, ['___store' => 'new-store', 'uenc' => null, '___from_store' => 'old-store']); - $this->switcher->getTargetStorePostData($store); + $this->switcher->getTargetStorePostData($storeMock); } /** @@ -104,7 +172,7 @@ public function testIsStoreInUrl($isUseStoreInUrl) $storeMock->expects($this->once())->method('isUseStoreInUrl')->willReturn($isUseStoreInUrl); - $this->storeManager->expects($this->any())->method('getStore')->willReturn($storeMock); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); $this->assertEquals($this->switcher->isStoreInUrl(), $isUseStoreInUrl); // check value is cached $this->assertEquals($this->switcher->isStoreInUrl(), $isUseStoreInUrl); @@ -114,7 +182,7 @@ public function testIsStoreInUrl($isUseStoreInUrl) * @see self::testIsStoreInUrlDataProvider() * @return array */ - public function isStoreInUrlDataProvider() + public function isStoreInUrlDataProvider(): array { return [[true], [false]]; } diff --git a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php index 907eb74e20fa2..f8aa09cb20a61 100644 --- a/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php +++ b/app/code/Magento/Store/Ui/Component/Listing/Column/Store/Options.php @@ -10,7 +10,7 @@ use Magento\Store\Model\System\Store as SystemStore; /** - * Class Options + * Ui stores options */ class Options implements OptionSourceInterface { @@ -93,37 +93,38 @@ protected function sanitizeName($name) * * @return void */ - protected function generateCurrentOptions() + protected function generateCurrentOptions(): void { $websiteCollection = $this->systemStore->getWebsiteCollection(); $groupCollection = $this->systemStore->getGroupCollection(); $storeCollection = $this->systemStore->getStoreCollection(); - /** @var \Magento\Store\Model\Website $website */ + foreach ($websiteCollection as $website) { $groups = []; - /** @var \Magento\Store\Model\Group $group */ foreach ($groupCollection as $group) { - if ($group->getWebsiteId() == $website->getId()) { + if ($group->getWebsiteId() === $website->getId()) { $stores = []; - /** @var \Magento\Store\Model\Store $store */ foreach ($storeCollection as $store) { - if ($store->getGroupId() == $group->getId()) { - $name = $this->sanitizeName($store->getName()); - $stores[$name]['label'] = str_repeat(' ', 8) . $name; - $stores[$name]['value'] = $store->getId(); + if ($store->getGroupId() === $group->getId()) { + $stores[] = [ + 'label' => str_repeat(' ', 8) . $this->sanitizeName($store->getName()), + 'value' => $store->getId(), + ]; } } if (!empty($stores)) { - $name = $this->sanitizeName($group->getName()); - $groups[$name]['label'] = str_repeat(' ', 4) . $name; - $groups[$name]['value'] = array_values($stores); + $groups[] = [ + 'label' => str_repeat(' ', 4) . $this->sanitizeName($group->getName()), + 'value' => array_values($stores), + ]; } } } if (!empty($groups)) { - $name = $this->sanitizeName($website->getName()); - $this->currentOptions[$name]['label'] = $name; - $this->currentOptions[$name]['value'] = array_values($groups); + $this->currentOptions[] = [ + 'label' => $this->sanitizeName($website->getName()), + 'value' => array_values($groups), + ]; } } } diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminSetUpWatermarkForSwatchImageTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminSetUpWatermarkForSwatchImageTest.xml index d56572afd8847..07ce30b702f91 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminSetUpWatermarkForSwatchImageTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminSetUpWatermarkForSwatchImageTest.xml @@ -38,8 +38,7 @@ </actionGroup> <!-- Select Edit next to the Default Store View --> <comment userInput="Select Edit next to the Default Store View" stepKey="commentEditDefaultView"/> - <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickToEditDefaultStoreView"/> - <waitForPageLoad stepKey="waitForDefaultStorePage"/> + <actionGroup ref="AdminClickFirstRowEditLinkOnCustomerGridActionGroup" stepKey="clickToEditDefaultStoreView"/> <!-- Expand the Product Image Watermarks section--> <comment userInput="Expand the Product Image Watermarks section" stepKey="commentOpenWatermarksSection"/> <click selector="{{AdminDesignConfigSection.watermarkSectionHeader}}" stepKey="clickToProductImageWatermarks"/> diff --git a/app/code/Magento/Translation/view/frontend/requirejs-config.js b/app/code/Magento/Translation/view/frontend/requirejs-config.js index b4b3ce0f8c554..9a99d49eddbcf 100644 --- a/app/code/Magento/Translation/view/frontend/requirejs-config.js +++ b/app/code/Magento/Translation/view/frontend/requirejs-config.js @@ -10,8 +10,5 @@ var config = { addClass: 'Magento_Translation/js/add-class', 'Magento_Translation/add-class': 'Magento_Translation/js/add-class' } - }, - deps: [ - 'mage/translate-inline' - ] + } }; diff --git a/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js b/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js index d675bd7a60ab5..7dcf0994ef56b 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js @@ -2,6 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +/* eslint-disable no-undef */ define([ 'jquery', 'Magento_Ui/js/grid/columns/column', @@ -32,7 +33,8 @@ define([ listens: { '${ $.provider }:params.filters': 'hide', '${ $.provider }:params.search': 'hide', - '${ $.provider }:params.paging': 'hide' + '${ $.provider }:params.paging': 'hide', + '${ $.provider }:data.items': 'updateDisplayedRecord' }, exports: { height: '${ $.parentName }.thumbnail_url:previewHeight' @@ -48,6 +50,25 @@ define([ this._super(); $(document).on('keydown', this.handleKeyDown.bind(this)); + this.lastOpenedImage.subscribe(function (newValue) { + + if (newValue === false && _.isNull(this.visibleRecord())) { + return; + } + + if (newValue === this.visibleRecord()) { + return; + } + + if (newValue === false) { + this.hide(); + + return; + } + + this.show(this.masonry().rows()[newValue]); + }.bind(this)); + return this; }, @@ -128,8 +149,6 @@ define([ * @param {Object} record */ show: function (record) { - var img; - if (record._rowIndex === this.visibleRecord()) { this.hide(); @@ -141,9 +160,21 @@ define([ this._selectRow(record.rowNumber || null); this.visibleRecord(record._rowIndex); - img = $(this.previewImageSelector + ' img'); + this.lastOpenedImage(record._rowIndex); + this.updateImageData(); + }, - if (img.get(0).complete) { + /** + * Update image data when image preview is opened + */ + updateImageData: function () { + var img = $(this.previewImageSelector + ' img'); + + if (!img.get(0)) { + setTimeout(function () { + this.updateImageData(); + }.bind(this), 100); + } else if (img.get(0).complete) { this.updateHeight(); this.scrollToPreview(); } else { @@ -152,8 +183,17 @@ define([ this.scrollToPreview(); }.bind(this)); } + }, - this.lastOpenedImage(record._rowIndex); + /** + * Update preview displayed record data from the new items data if the preview is expanded + * + * @param {Array} items + */ + updateDisplayedRecord: function (items) { + if (!_.isNull(this.visibleRecord())) { + this.displayedRecord(items[this.visibleRecord()]); + } }, /** diff --git a/app/code/Magento/Ui/view/base/web/js/grid/url-filter-applier.js b/app/code/Magento/Ui/view/base/web/js/grid/url-filter-applier.js index 1f870e9e819a1..be9044143c5a4 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/url-filter-applier.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/url-filter-applier.js @@ -5,8 +5,9 @@ define([ 'uiComponent', - 'underscore' -], function (Component, _) { + 'underscore', + 'jquery' +], function (Component, _, $) { 'use strict'; return Component.extend({ @@ -36,7 +37,9 @@ define([ * Apply filter */ apply: function () { - var urlFilter = this.getFilterParam(this.searchString); + var urlFilter = this.getFilterParam(this.searchString), + applied, + filters; if (_.isUndefined(this.filterComponent())) { setTimeout(function () { @@ -47,8 +50,9 @@ define([ } if (Object.keys(urlFilter).length) { - this.filterComponent().setData(urlFilter, false); - this.filterComponent().apply(); + applied = this.filterComponent().get('applied'); + filters = $.extend({}, applied, urlFilter); + this.filterComponent().set('applied', filters); } }, diff --git a/app/code/Magento/Wishlist/Controller/Shared/Allcart.php b/app/code/Magento/Wishlist/Controller/Shared/Allcart.php index 6300b14dcf515..89413eff8323f 100644 --- a/app/code/Magento/Wishlist/Controller/Shared/Allcart.php +++ b/app/code/Magento/Wishlist/Controller/Shared/Allcart.php @@ -3,13 +3,24 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Wishlist\Controller\Shared; +use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; -use Magento\Wishlist\Model\ItemCarrier; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\Controller\Result\Forward; +use Magento\Framework\Controller\Result\Redirect; use Magento\Framework\Controller\ResultFactory; +use Magento\Wishlist\Model\ItemCarrier; -class Allcart extends \Magento\Framework\App\Action\Action +/** + * Wishlist Allcart Controller + */ +class Allcart extends Action implements HttpGetActionInterface, HttpPostActionInterface { /** * @var WishlistProvider @@ -17,7 +28,7 @@ class Allcart extends \Magento\Framework\App\Action\Action protected $wishlistProvider; /** - * @var \Magento\Wishlist\Model\ItemCarrier + * @var ItemCarrier */ protected $itemCarrier; @@ -39,21 +50,22 @@ public function __construct( /** * Add all items from wishlist to shopping cart * - * @return \Magento\Framework\Controller\ResultInterface + * {@inheritDoc} */ public function execute() { $wishlist = $this->wishlistProvider->getWishlist(); if (!$wishlist) { - /** @var \Magento\Framework\Controller\Result\Forward $resultForward */ + /** @var Forward $resultForward */ $resultForward = $this->resultFactory->create(ResultFactory::TYPE_FORWARD); $resultForward->forward('noroute'); return $resultForward; } $redirectUrl = $this->itemCarrier->moveAllToCart($wishlist, $this->getRequest()->getParam('qty')); - /** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */ + /** @var Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); $resultRedirect->setUrl($redirectUrl); + return $resultRedirect; } } diff --git a/app/code/Magento/Wishlist/Controller/Shared/Cart.php b/app/code/Magento/Wishlist/Controller/Shared/Cart.php index c0a394ce9d762..939cbe3a2c46f 100644 --- a/app/code/Magento/Wishlist/Controller/Shared/Cart.php +++ b/app/code/Magento/Wishlist/Controller/Shared/Cart.php @@ -13,7 +13,7 @@ use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context as ActionContext; use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\Controller\Result\Redirect as ResultRedirect; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Escaper; use Magento\Framework\Exception\LocalizedException; @@ -124,9 +124,11 @@ public function execute() } catch (\Exception $e) { $this->messageManager->addExceptionMessage($e, __('We can\'t add the item to the cart right now.')); } - /** @var Redirect $resultRedirect */ + + /** @var ResultRedirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); $resultRedirect->setUrl($redirectUrl); + return $resultRedirect; } } diff --git a/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/AllcartTest.php b/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/AllcartTest.php index eea3346e8e81b..d9339af8144f4 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/AllcartTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/AllcartTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + declare(strict_types=1); namespace Magento\Wishlist\Test\Unit\Controller\Shared; @@ -20,83 +21,60 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +/** + * Test for \Magento\Wishlist\Controller\Shared\Allcart. + */ class AllcartTest extends TestCase { /** * @var Allcart */ - protected $allcartController; - - /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager - */ - protected $objectManagerHelper; - - /** - * @var Context - */ - protected $context; + private $allcartController; /** * @var WishlistProvider|MockObject */ - protected $wishlistProviderMock; + private $wishlistProviderMock; /** * @var ItemCarrier|MockObject */ - protected $itemCarrierMock; + private $itemCarrierMock; /** * @var Wishlist|MockObject */ - protected $wishlistMock; + private $wishlistMock; /** * @var Http|MockObject */ - protected $requestMock; - - /** - * @var ResultFactory|MockObject - */ - protected $resultFactoryMock; + private $requestMock; /** * @var Redirect|MockObject */ - protected $resultRedirectMock; + private $resultRedirectMock; /** * @var Forward|MockObject */ - protected $resultForwardMock; + private $resultForwardMock; + /** + * @inheritDoc + */ protected function setUp(): void { - $this->wishlistProviderMock = $this->getMockBuilder(WishlistProvider::class) - ->disableOriginalConstructor() - ->getMock(); - $this->itemCarrierMock = $this->getMockBuilder(ItemCarrier::class) - ->disableOriginalConstructor() - ->getMock(); - $this->wishlistMock = $this->getMockBuilder(Wishlist::class) - ->disableOriginalConstructor() - ->getMock(); - $this->requestMock = $this->getMockBuilder(Http::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultRedirectMock = $this->getMockBuilder(Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultForwardMock = $this->getMockBuilder(Forward::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultFactoryMock->expects($this->any()) + $this->wishlistProviderMock = $this->createMock(WishlistProvider::class); + $this->itemCarrierMock = $this->createMock(ItemCarrier::class); + $this->wishlistMock = $this->createMock(Wishlist::class); + $this->requestMock = $this->createMock(Http::class); + $resultFactoryMock = $this->createMock(ResultFactory::class); + $this->resultRedirectMock = $this->createMock(Redirect::class); + $this->resultForwardMock = $this->createMock(Forward::class); + + $resultFactoryMock->expects($this->any()) ->method('create') ->willReturnMap( [ @@ -105,18 +83,18 @@ protected function setUp(): void ] ); - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->context = $this->objectManagerHelper->getObject( + $objectManagerHelper = new ObjectManagerHelper($this); + $context = $objectManagerHelper->getObject( Context::class, [ 'request' => $this->requestMock, - 'resultFactory' => $this->resultFactoryMock + 'resultFactory' => $resultFactoryMock ] ); - $this->allcartController = $this->objectManagerHelper->getObject( + $this->allcartController = $objectManagerHelper->getObject( Allcart::class, [ - 'context' => $this->context, + 'context' => $context, 'wishlistProvider' => $this->wishlistProviderMock, 'itemCarrier' => $this->itemCarrierMock ] diff --git a/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/CartTest.php b/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/CartTest.php index 923b33ef4748b..e6a127457a6c6 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/CartTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Controller/Shared/CartTest.php @@ -8,6 +8,7 @@ namespace Magento\Wishlist\Test\Unit\Controller\Shared; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Exception; use Magento\Checkout\Helper\Cart as CartHelper; use Magento\Checkout\Model\Cart; use Magento\Framework\App\Action\Context as ActionContext; @@ -29,156 +30,146 @@ use PHPUnit\Framework\TestCase; /** + * Test for \Magento\Wishlist\Controller\Shared\Cart. + * * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CartTest extends TestCase { - /** @var SharedCart|MockObject */ - protected $model; - - /** @var RequestInterface|MockObject */ - protected $request; - - /** @var ManagerInterface|MockObject */ - protected $messageManager; - - /** @var ActionContext|MockObject */ - protected $context; - - /** @var Cart|MockObject */ - protected $cart; + /** + * @var SharedCart|MockObject + */ + private $model; - /** @var CartHelper|MockObject */ - protected $cartHelper; + /** + * @var RequestInterface|MockObject + */ + private $request; - /** @var Quote|MockObject */ - protected $quote; + /** + * @var ManagerInterface|MockObject + */ + private $messageManager; - /** @var OptionCollection|MockObject */ - protected $optionCollection; + /** + * @var Cart|MockObject + */ + private $cart; - /** @var OptionFactory|MockObject */ - protected $optionFactory; + /** + * @var CartHelper|MockObject + */ + private $cartHelper; - /** @var Option|MockObject */ - protected $option; + /** + * @var Quote|MockObject + */ + private $quote; - /** @var ItemFactory|MockObject */ - protected $itemFactory; + /** + * @var OptionCollection|MockObject + */ + private $optionCollection; - /** @var Item|MockObject */ - protected $item; + /** + * @var Option|MockObject + */ + private $option; - /** @var Escaper|MockObject */ - protected $escaper; + /** + * @var Item|MockObject + */ + private $item; - /** @var RedirectInterface|MockObject */ - protected $redirect; + /** + * @var Escaper|MockObject + */ + private $escaper; - /** @var ResultFactory|MockObject */ - protected $resultFactory; + /** + * @var RedirectInterface|MockObject + */ + private $redirect; - /** @var Redirect|MockObject */ - protected $resultRedirect; + /** + * @var Redirect|MockObject + */ + private $resultRedirect; - /** @var Product|MockObject */ - protected $product; + /** + * @var Product|MockObject + */ + private $product; + /** + * @inheritDoc + */ protected function setUp(): void { - $this->request = $this->getMockBuilder(RequestInterface::class) - ->getMockForAbstractClass(); - - $this->redirect = $this->getMockBuilder(RedirectInterface::class) - ->getMockForAbstractClass(); - - $this->messageManager = $this->getMockBuilder(ManagerInterface::class) - ->getMockForAbstractClass(); - - $this->resultRedirect = $this->getMockBuilder(Redirect::class) - ->disableOriginalConstructor() - ->getMock(); + $this->request = $this->getMockForAbstractClass(RequestInterface::class); + $this->redirect = $this->getMockForAbstractClass(RedirectInterface::class); + $this->messageManager = $this->getMockForAbstractClass(ManagerInterface::class); + $this->resultRedirect = $this->createMock(Redirect::class); - $this->resultFactory = $this->getMockBuilder(ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultFactory->expects($this->once()) + $resultFactory = $this->createMock(ResultFactory::class); + $resultFactory->expects($this->once()) ->method('create') ->with(ResultFactory::TYPE_REDIRECT) ->willReturn($this->resultRedirect); - $this->context = $this->getMockBuilder(\Magento\Framework\App\Action\Context::class) + /** @var ActionContext|MockObject $context */ + $context = $this->getMockBuilder(ActionContext::class) ->disableOriginalConstructor() ->getMock(); - $this->context->expects($this->any()) + $context->expects($this->any()) ->method('getRequest') ->willReturn($this->request); - $this->context->expects($this->any()) + $context->expects($this->any()) ->method('getRedirect') ->willReturn($this->redirect); - $this->context->expects($this->any()) + $context->expects($this->any()) ->method('getMessageManager') ->willReturn($this->messageManager); - $this->context->expects($this->any()) + $context->expects($this->any()) ->method('getResultFactory') - ->willReturn($this->resultFactory); - - $this->cart = $this->getMockBuilder(\Magento\Checkout\Model\Cart::class) - ->disableOriginalConstructor() - ->getMock(); + ->willReturn($resultFactory); - $this->cartHelper = $this->getMockBuilder(\Magento\Checkout\Helper\Cart::class) - ->disableOriginalConstructor() - ->getMock(); + $this->cart = $this->createMock(Cart::class); + $this->cartHelper = $this->createMock(CartHelper::class); $this->quote = $this->getMockBuilder(Quote::class) ->disableOriginalConstructor() - ->setMethods(['getHasError']) + ->addMethods(['getHasError']) ->getMock(); - $this->optionCollection = $this->getMockBuilder( - \Magento\Wishlist\Model\ResourceModel\Item\Option\Collection::class - )->disableOriginalConstructor() - ->getMock(); + $this->optionCollection = $this->createMock(OptionCollection::class); $this->option = $this->getMockBuilder(Option::class) ->disableOriginalConstructor() ->getMock(); - $this->optionFactory = $this->getMockBuilder(OptionFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->optionFactory->expects($this->once()) + /** @var OptionFactory|MockObject $optionFactory */ + $optionFactory = $this->createMock(OptionFactory::class); + $optionFactory->expects($this->once()) ->method('create') ->willReturn($this->option); - $this->item = $this->getMockBuilder(Item::class) - ->disableOriginalConstructor() - ->getMock(); + $this->item = $this->createMock(Item::class); - $this->itemFactory = $this->getMockBuilder(ItemFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->itemFactory->expects($this->once()) + $itemFactory = $this->createMock(ItemFactory::class); + $itemFactory->expects($this->once()) ->method('create') ->willReturn($this->item); - $this->escaper = $this->getMockBuilder(Escaper::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->product = $this->getMockBuilder(Product::class) - ->disableOriginalConstructor() - ->getMock(); + $this->escaper = $this->createMock(Escaper::class); + $this->product = $this->createMock(Product::class); $this->model = new SharedCart( - $this->context, + $context, $this->cart, - $this->optionFactory, - $this->itemFactory, + $optionFactory, + $itemFactory, $this->cartHelper, $this->escaper ); @@ -358,7 +349,7 @@ public function testExecuteProductException() $this->option->expects($this->once()) ->method('getCollection') - ->willThrowException(new \Magento\Catalog\Model\Product\Exception(__('LocalizedException'))); + ->willThrowException(new Exception(__('LocalizedException'))); $this->resultRedirect->expects($this->once()) ->method('setUrl') diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less index 5bdaa4c3c35a3..690b89f42b419 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_extends.less +++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less @@ -1110,7 +1110,7 @@ .abs-shopping-cart-items { .action { &.continue { - border-radius: 3px; + border-radius: @button__border-radius; font-weight: @font-weight__bold; .lib-link-as-button(); .lib-button( diff --git a/app/design/frontend/Magento/blank/web/css/source/_typography.less b/app/design/frontend/Magento/blank/web/css/source/_typography.less index 6807c0f692af8..02ccd90d4655d 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_typography.less +++ b/app/design/frontend/Magento/blank/web/css/source/_typography.less @@ -9,7 +9,7 @@ & when (@media-common = true) { .lib-font-face( - @family-name: @font-family-name__base, + @family-name: 'Open Sans', @font-path: '@{baseDir}fonts/opensans/light/opensans-300', @font-weight: 300, @font-style: normal, @@ -17,7 +17,7 @@ ); .lib-font-face( - @family-name: @font-family-name__base, + @family-name: 'Open Sans', @font-path: '@{baseDir}fonts/opensans/regular/opensans-400', @font-weight: 400, @font-style: normal, @@ -25,7 +25,7 @@ ); .lib-font-face( - @family-name: @font-family-name__base, + @family-name: 'Open Sans', @font-path: '@{baseDir}fonts/opensans/semibold/opensans-600', @font-weight: 600, @font-style: normal, @@ -33,7 +33,7 @@ ); .lib-font-face( - @family-name: @font-family-name__base, + @family-name: 'Open Sans', @font-path: '@{baseDir}fonts/opensans/bold/opensans-700', @font-weight: 700, @font-style: normal, diff --git a/app/etc/di.xml b/app/etc/di.xml index fed2e336046f9..585c88f68ff6f 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -185,6 +185,7 @@ <preference for="Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface" type="Magento\Framework\Setup\Declaration\Schema\Db\MySQL\DbSchemaWriter" /> <preference for="Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface" type="Magento\Framework\Setup\Declaration\Schema\SchemaConfig" /> <preference for="Magento\Framework\Setup\Declaration\Schema\DataSavior\DumpAccessorInterface" type="Magento\Framework\Setup\Declaration\Schema\FileSystem\Csv" /> + <preference for="Magento\Framework\MessageQueue\ConfigInterface" type="Magento\Framework\MessageQueue\Config\Proxy" /> <preference for="Magento\Framework\MessageQueue\PublisherInterface" type="Magento\Framework\MessageQueue\PublisherPool" /> <preference for="Magento\Framework\MessageQueue\BulkPublisherInterface" type="Magento\Framework\MessageQueue\Bulk\PublisherPool" /> <preference for="Magento\Framework\MessageQueue\MessageIdGeneratorInterface" type="Magento\Framework\MessageQueue\MessageIdGenerator" /> diff --git a/dev/tests/integration/testsuite/Magento/Store/Ui/Component/Listing/Column/Store/OptionsTest.php b/dev/tests/integration/testsuite/Magento/Store/Ui/Component/Listing/Column/Store/OptionsTest.php new file mode 100644 index 0000000000000..e13c4a427464f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/Ui/Component/Listing/Column/Store/OptionsTest.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Ui\Component\Listing\Column\Store; + +use Magento\Store\Model\ResourceModel\Group as GroupResource; +use Magento\Store\Model\ResourceModel\Store as StoreResource; +use Magento\Store\Model\ResourceModel\Website as WebsiteResource; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Test for \Magento\Store\Ui\Component\Listing\Column\Store\Options. + */ +class OptionsTest extends TestCase +{ + private const DEFAULT_WEBSITE_NAME = 'Main Website'; + private const DEFAULT_STORE_GROUP_NAME = 'Main Website Store'; + private const DEFAULT_STORE_NAME = 'Default Store View'; + + /** + * @var OptionsFactory + */ + private $modelFactory; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var WebsiteResource + */ + private $websiteResource; + + /** + * @var StoreResource + */ + private $storeResource; + + /** + * @var GroupResource + */ + private $groupResource; + + /** + * @return void + */ + protected function setUp(): void + { + $objectManager = Bootstrap::getObjectManager(); + + $this->modelFactory = $objectManager->get(OptionsFactory::class); + $this->storeManager = $objectManager->get(StoreManagerInterface::class); + + $this->websiteResource = $objectManager->get(WebsiteResource::class); + $this->groupResource = $objectManager->get(GroupResource::class); + $this->storeResource = $objectManager->get(StoreResource::class); + } + + /** + * To option array test with duplicate website, store group, store view names + * + * @magentoDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php + * + * @return void + */ + public function testToOptionArray(): void + { + $website = $this->storeManager->getWebsite('test'); + $this->websiteResource->save($website->setName(self::DEFAULT_WEBSITE_NAME)); + + $storeGroup = current($website->getGroups()); + $this->groupResource->save($storeGroup->setName(self::DEFAULT_STORE_GROUP_NAME)); + + $store = current($website->getStores()); + $this->storeResource->save($store->setName(self::DEFAULT_STORE_NAME)); + + $model = $this->modelFactory->create(); + $storeIds = [$this->storeManager->getStore('default')->getId(), $store->getId()]; + + $this->assertEquals($this->getExpectedOptions($storeIds), $model->toOptionArray()); + } + + /** + * Returns expected options + * + * @param array $storeIds + * @return array + */ + private function getExpectedOptions(array $storeIds): array + { + $expectedOptions = []; + foreach ($storeIds as $storeId) { + $expectedOptions[] = [ + 'label' => self::DEFAULT_WEBSITE_NAME, + 'value' => [[ + 'label' => str_repeat(' ', 4) . self::DEFAULT_STORE_GROUP_NAME, + 'value' => [[ + 'label' => str_repeat(' ', 8) . self::DEFAULT_STORE_NAME, + 'value' => $storeId, + ]], + ]], + ]; + } + + return $expectedOptions; + } +} diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js index 6a466f0c37872..a5b434d956097 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js @@ -74,6 +74,7 @@ define([ originMock = $.fn.get; spyOn($.fn, 'get').and.returnValue(imageMock); + imagePreview.lastOpenedImage = jasmine.createSpy().and.returnValue(2); imagePreview.visibleRecord = jasmine.createSpy().and.returnValue(2); imagePreview.displayedRecord = ko.observable(); imagePreview.displayedRecord(recordMock); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/url-filter-applier.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/url-filter-applier.test.js index a3d49e382de51..1e63f9f61f6d1 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/url-filter-applier.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/url-filter-applier.test.js @@ -12,7 +12,8 @@ define([ describe('Magento_Ui/js/grid/url-filter-applier', function () { var urlFilterApplierObj, filterComponentMock = { - setData: jasmine.createSpy(), + set: jasmine.createSpy(), + get: jasmine.createSpy(), apply: jasmine.createSpy() }; @@ -64,11 +65,14 @@ define([ it('applies url filter on filter component', function () { urlFilterApplierObj.searchString = '?filters[name]=test&filters[qty]=1'; urlFilterApplierObj.apply(); - expect(urlFilterApplierObj.filterComponent().setData).toHaveBeenCalledWith({ - 'name': 'test', - 'qty': '1' - }, false); - expect(urlFilterApplierObj.filterComponent().apply).toHaveBeenCalled(); + expect(urlFilterApplierObj.filterComponent().get).toHaveBeenCalled(); + expect(urlFilterApplierObj.filterComponent().set).toHaveBeenCalledWith( + 'applied', + { + 'name': 'test', + 'qty': '1' + } + ); }); }); }); diff --git a/lib/internal/Magento/Framework/Registry.php b/lib/internal/Magento/Framework/Registry.php index e798b28e1e1b2..b5944729fd1a1 100644 --- a/lib/internal/Magento/Framework/Registry.php +++ b/lib/internal/Magento/Framework/Registry.php @@ -9,7 +9,7 @@ * Registry model. Used to manage values in registry * * Registry usage as a shared service introduces temporal, hard to detect coupling into system. - * It's usage should be avoid. Use service classes or data providers instead. + * Its usage should be avoided. Use service classes or data providers instead. * * @api * @deprecated 102.0.0 diff --git a/lib/web/mage/translate-inline.js b/lib/web/mage/translate-inline.js index 56acef5a49a42..2407a64e5e0d1 100644 --- a/lib/web/mage/translate-inline.js +++ b/lib/web/mage/translate-inline.js @@ -6,9 +6,10 @@ define([ 'jquery', 'mage/template', - 'jquery-ui-modules/dialog', - 'mage/translate' -], function ($, mageTemplate) { + 'mage/utils/misc', + 'mage/translate', + 'jquery-ui-modules/dialog' +], function ($, mageTemplate, miscUtils) { 'use strict'; $.widget('mage.translateInline', $.ui.dialog, { @@ -59,11 +60,12 @@ define([ * Open. */ open: function () { - var topMargin; + var $uiDialog = $(this).closest('.ui-dialog'), + topMargin = $uiDialog.children('.ui-dialog-titlebar').outerHeight() + 45; - $(this).closest('.ui-dialog').addClass('ui-dialog-active'); - topMargin = jQuery(this).closest('.ui-dialog').children('.ui-dialog-titlebar').outerHeight() + 45; - jQuery(this).closest('.ui-dialog').css('margin-top', topMargin); + $uiDialog + .addClass('ui-dialog-active') + .css('margin-top', topMargin); }, /** @@ -79,11 +81,15 @@ define([ * @protected */ _create: function () { + var $translateArea = $(this.options.translateArea); + + if (!$translateArea.length) { + $translateArea = $('body'); + } + $translateArea.on('edit.editTrigger', $.proxy(this._onEdit, this)); + this.tmpl = mageTemplate(this.options.translateForm.template); - (this.options.translateArea && $(this.options.translateArea).length ? - $(this.options.translateArea) : - this.element.closest('body')) - .on('edit.editTrigger', $.proxy(this._onEdit, this)); + this._super(); }, @@ -95,7 +101,7 @@ define([ _prepareContent: function (templateData) { var data = $.extend({ items: templateData, - escape: $.mage.escapeHTML + escape: miscUtils.escape }, this.options.translateForm.data); this.data = data; @@ -131,12 +137,11 @@ define([ * @protected */ _formSubmit: function () { - var parameters; + var parameters = $.param({ + area: this.options.area + }) + '&' + $('#' + this.options.translateForm.data.id).serialize(); this.formIsSubmitted = true; - parameters = $.param({ - area: this.options.area - }) + '&' + $('#' + this.options.translateForm.data.id).serialize(); $.ajax({ url: this.options.ajaxUrl, @@ -162,11 +167,13 @@ define([ * @private */ _updatePlaceholder: function (newValue) { - var target = jQuery(this.target); + var $target = $(this.target), + translateObject = $target.data('translate')[0]; + + translateObject.shown = newValue; + translateObject.translated = newValue; - target.data('translate')[0].shown = newValue; - target.data('translate')[0].translated = newValue; - target.html(newValue); + $target.html(newValue); }, /** @@ -177,20 +184,6 @@ define([ this._super(); } }); - // @TODO move the "escapeHTML" method into the file with global utility functions - $.extend(true, $, { - mage: { - /** - * @param {String} str - * @return {Boolean} - */ - escapeHTML: function (str) { - return str ? - jQuery('<div/>').text(str).html().replace(/"/g, '"') : - false; - } - } - }); return $.mage.translateInline; }); diff --git a/lib/web/mage/utils/misc.js b/lib/web/mage/utils/misc.js index 3829f5ed467e2..b1c0c33324c28 100644 --- a/lib/web/mage/utils/misc.js +++ b/lib/web/mage/utils/misc.js @@ -6,8 +6,8 @@ define([ 'underscore', 'jquery', - 'FormData' -], function (_, $) { + 'mage/utils/objects' +], function (_, $, utils) { 'use strict'; var defaultAttributes, @@ -120,7 +120,7 @@ define([ */ submit: function (options, attrs) { var form = document.createElement('form'), - data = this.serialize(options.data), + data = utils.serialize(options.data), attributes = _.extend({}, defaultAttributes, attrs || {}); if (!attributes.action) { @@ -205,11 +205,11 @@ define([ if (type === 'default') { formData = new FormData(); - _.each(this.serialize(data), function (val, name) { + _.each(utils.serialize(data), function (val, name) { formData.append(name, val); }); } else if (type === 'simple') { - formData = this.serialize(data); + formData = utils.serialize(data); } return formData; @@ -242,6 +242,16 @@ define([ return data; }, + /** + * Replaces special characters with their corresponding HTML entities. + * + * @param {String} string - Text to escape. + * @returns {String} Escaped text. + */ + escape: function (string) { + return string ? $('<p/>').text(string).html().replace(/"/g, '"') : string; + }, + /** * Replaces symbol codes with their unescaped counterparts. * diff --git a/lib/web/mage/utils/objects.js b/lib/web/mage/utils/objects.js index 83711c43d2d1b..82866c0f2a6ad 100644 --- a/lib/web/mage/utils/objects.js +++ b/lib/web/mage/utils/objects.js @@ -5,8 +5,9 @@ define([ 'ko', 'jquery', - 'underscore' -], function (ko, $, _) { + 'underscore', + 'mage/utils/strings' +], function (ko, $, _, stringUtils) { 'use strict'; var primitives = [ @@ -217,7 +218,7 @@ define([ data = this.flatten(data); _.each(data, function (value, keys) { - keys = this.serializeName(keys); + keys = stringUtils.serializeName(keys); value = _.isUndefined(value) ? '' : value; result[keys] = value; diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php index e864a81ffcc0e..4a3a02b37a6ab 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php @@ -40,7 +40,7 @@ class Session implements ConfigOptionsListInterface const INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS = 'session-save-redis-sentinel-servers'; const INPUT_KEY_SESSION_REDIS_SENTINEL_MASTER = 'session-save-redis-sentinel-master'; const INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER = 'session-save-redis-sentinel-verify-master'; - const INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES = 'session-save-redis-sentinel-connect-retires'; + const INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES = 'session-save-redis-sentinel-connect-retries'; const CONFIG_PATH_SESSION_REDIS = 'session/redis'; const CONFIG_PATH_SESSION_REDIS_HOST = 'session/redis/host';