diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddCostPriceToProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddCostPriceToProductActionGroup.xml new file mode 100644 index 000000000000..446a3032578d --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddCostPriceToProductActionGroup.xml @@ -0,0 +1,28 @@ + + + + + + + Sets the provided Cost Price on the Admin Product creation/edit page. + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 0436609c7e73..2122760363c8 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -1488,4 +1488,35 @@ Simple Product with special characters in SKU s000&01 + + Product1 + product-1 + product1 + 200.00 + 100 + 1 + 150.00 + None + simple + 4 + 1 + EavStockItem + CustomAttributeCategoryIds + + + product2 + Product2 + product-2 + 300.00 + 300 + 1 + IN STOCK + 250.00 + Taxable Goods + simple + 4 + 1 + EavStockItem + CustomAttributeCategoryIds + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormCostPricingSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormCostPricingSection.xml new file mode 100644 index 000000000000..2ea5d9e0bdb4 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormCostPricingSection.xml @@ -0,0 +1,14 @@ + + + +
+ + +
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml index 57824d73f4d7..1c704a373b05 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml @@ -46,6 +46,7 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml index 744b279e4c77..4c4dedb521d2 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml @@ -45,5 +45,6 @@ + diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml index 08ecef34337c..be7f0e0ed98e 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml @@ -75,6 +75,7 @@ + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUKCustomerCheckoutWithCouponTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUKCustomerCheckoutWithCouponTest.xml index 6ea870cf4183..b04688ffdc3a 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUKCustomerCheckoutWithCouponTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontUKCustomerCheckoutWithCouponTest.xml @@ -94,7 +94,7 @@ - + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetCalculationClassForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetCalculationClassForShippingActionGroup.xml new file mode 100644 index 000000000000..06c465c140a1 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetCalculationClassForShippingActionGroup.xml @@ -0,0 +1,30 @@ + + + + + + + Goes to the 'Configuration' page for 'Tax Calculation Method Based On'. Sets 'Unit Price' to 'Total'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetIncludeTaxInTotalForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetIncludeTaxInTotalForShippingActionGroup.xml new file mode 100644 index 000000000000..3cc913650e72 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetIncludeTaxInTotalForShippingActionGroup.xml @@ -0,0 +1,35 @@ + + + + + + + Goes to the 'Configuration' page for 'Orders, Invoices, Credit Memos Display Settings'. Sets 'Yes' to 'No'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetOrderInvoiceSettingsForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetOrderInvoiceSettingsForShippingActionGroup.xml new file mode 100644 index 000000000000..fb88ad7e6b17 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ResetOrderInvoiceSettingsForShippingActionGroup.xml @@ -0,0 +1,29 @@ + + + + + + + Goes to the 'Configuration' page for 'Orders, Invoices, Credit Memos Display Settings'. Sets 'Display Subtotal' to 'Excluding Tax'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/SetCalculationSettingsForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetCalculationSettingsForShippingActionGroup.xml new file mode 100644 index 000000000000..2a76b58768c3 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetCalculationSettingsForShippingActionGroup.xml @@ -0,0 +1,30 @@ + + + + + + + Goes to the 'Configuration' page for 'Tax'. Sets 'Tax Calculation Method Based On' to 'Unit Price'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/SetIncludeTaxInTotalForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetIncludeTaxInTotalForShippingActionGroup.xml new file mode 100644 index 000000000000..36919c9c70ca --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetIncludeTaxInTotalForShippingActionGroup.xml @@ -0,0 +1,38 @@ + + + + + + + Goes to the 'Configuration' page for 'Orders, Invoices, Credit Memos Display Settings'. Sets 'No' to 'Yes'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/SetOrderInvoiceSettingsForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetOrderInvoiceSettingsForShippingActionGroup.xml new file mode 100644 index 000000000000..60a0cac2f810 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetOrderInvoiceSettingsForShippingActionGroup.xml @@ -0,0 +1,29 @@ + + + + + + + Goes to the 'Configuration' page for 'Orders, Invoices, Credit Memos Display Settings'. Sets 'Display Subtotal' to 'Include and Excluded tax'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/SetTaxClassForShippingActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetTaxClassForShippingActionGroup.xml index a0f05405ba0c..cf8b4e9d7d92 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/SetTaxClassForShippingActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/SetTaxClassForShippingActionGroup.xml @@ -12,13 +12,15 @@ Goes to the 'Configuration' page for 'Tax'. Sets 'Tax Class for Shipping' to 'Taxable Goods'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded. - + + + - + diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml index 9e2b314c5457..94be7f34c01b 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminConfigSection.xml @@ -28,5 +28,6 @@ + diff --git a/app/code/Magento/Cookie/etc/di.xml b/app/code/Magento/Cookie/etc/di.xml index 8b53209f5191..ba3813a2a577 100644 --- a/app/code/Magento/Cookie/etc/di.xml +++ b/app/code/Magento/Cookie/etc/di.xml @@ -7,5 +7,6 @@ --> + diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/MultiShippingWithCreationNewCustomerAndAddressesDuringCheckoutTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/MultiShippingWithCreationNewCustomerAndAddressesDuringCheckoutTest.xml similarity index 78% rename from app/code/Magento/Shipping/Test/Mftf/Test/MultiShippingWithCreationNewCustomerAndAddressesDuringCheckoutTest.xml rename to app/code/Magento/Multishipping/Test/Mftf/Test/MultiShippingWithCreationNewCustomerAndAddressesDuringCheckoutTest.xml index f97dc3f30ab7..dca1537e9d2d 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Test/MultiShippingWithCreationNewCustomerAndAddressesDuringCheckoutTest.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/MultiShippingWithCreationNewCustomerAndAddressesDuringCheckoutTest.xml @@ -14,17 +14,11 @@ - - - - - - - + simple product @@ -37,6 +31,7 @@ + @@ -44,38 +39,39 @@ + + + + + + - - + - + - - - - - - + + - + - - - + + + @@ -102,8 +98,8 @@ - - + + @@ -117,6 +113,7 @@ + @@ -143,9 +140,9 @@ - - - + + + @@ -156,10 +153,10 @@ - + - - + + diff --git a/app/code/Magento/PageCache/Model/App/Response/HttpPlugin.php b/app/code/Magento/PageCache/Model/App/Response/HttpPlugin.php index a6949cccc1ad..abc33da5e59b 100644 --- a/app/code/Magento/PageCache/Model/App/Response/HttpPlugin.php +++ b/app/code/Magento/PageCache/Model/App/Response/HttpPlugin.php @@ -22,10 +22,12 @@ class HttpPlugin */ public function beforeSendResponse(HttpResponse $subject) { - if ($subject instanceof NotCacheableInterface || $subject->headersSent()) { + if ($subject instanceof NotCacheableInterface + || $subject->headersSent() + || $subject->getMetadata("NotCacheable") + ) { return; } - $subject->sendVary(); } } diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/AdminPayPalExpressCheckoutTest.xml b/app/code/Magento/Paypal/Test/Mftf/Test/AdminPayPalExpressCheckoutTest.xml new file mode 100644 index 000000000000..e474f888096f --- /dev/null +++ b/app/code/Magento/Paypal/Test/Mftf/Test/AdminPayPalExpressCheckoutTest.xml @@ -0,0 +1,74 @@ + + + + + + + + + <description value="Place an order using paypal express checkout as payment method"/> + <severity value="CRITICAL"/> + <testCaseId value="AC-6149"/> + <group value="3rd_party_integration"/> + <group value="paypalExpress"/> + <group value="pr_exclude"/> + </annotations> + <before> + <!-- Simple product is created --> + <createData entity="SimpleProduct" stepKey="createProduct"> + <field key="price">10.00</field> + </createData> + <!-- US Customer is created --> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <!-- Go to StoreFront --> + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToStoreFront"/> + <!-- Add product to cart --> + <actionGroup ref="AddSimpleProductToCartActionGroup" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <!-- Goto Checkout Page --> + <actionGroup ref="StorefrontOpenCheckoutPageActionGroup" stepKey="goToCheckout"/> + <!--Fill Shipping Address--> + <actionGroup ref="GuestCheckoutFillNewShippingAddressActionGroup" stepKey="fillShippingAddress"> + <argument name="customer" value="$$createCustomer$$" /> + <argument name="address" value="US_Address_TX"/> + </actionGroup> + <!-- Select shipping --> + <actionGroup ref="StorefrontSetShippingMethodActionGroup" stepKey="selectShippingMethodAsFlatRate"> + <argument name="shippingMethodName" value="Flat Rate"/> + </actionGroup> + <actionGroup ref="StorefrontCheckoutClickNextOnShippingStepActionGroup" stepKey="goToCheckoutPaymentPage"/> + <!-- Click on PayPal payment radio button --> + <waitForElementClickable selector="{{CheckoutPaymentSection.PayPalPaymentRadio}}" stepKey="waitForPayPalRadioButton"/> + <click selector="{{CheckoutPaymentSection.PayPalPaymentRadio}}" stepKey="selectPaypalPayment"/> + <actionGroup ref="SwitchToPayPalGroupBtnActionGroup" stepKey="clickPayPalBtn"/> + <!-- Login to Paypal in-context and verify order total on paypal page--> + <actionGroup ref="StorefrontLoginToPayPalPaymentAccountTwoStepActionGroup" stepKey="loginToPayPal"/> + <actionGroup ref="StorefrontPaypalSwitchBackToMagentoFromCheckoutPageActionGroup" stepKey="confirmPaymentAndGoBackToMagento"/> + <!-- I see order successful Page --> + <waitForElementVisible selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="waitForOrderNumberToBeGrabbed"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <waitForText selector="{{CheckoutSuccessMainSection.success}}" userInput="We'll email you an order confirmation with details and tracking info." stepKey="seeSuccessMessage"/> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openOrder"> + <argument name="orderId" value="{$grabOrderNumber}"/> + </actionGroup> + <waitForElementVisible selector="{{AdminOrderPaymentInformationSection.paymentInformationField('Last Transaction ID')}}" stepKey="waitForTransactionIDFieldToBeAppeared"/> + <grabTextFrom selector="{{AdminOrderPaymentInformationSection.paymentInformationField('Last Transaction ID')}}" stepKey="grabTransactionID"/> + <waitForText selector="{{AdminOrderTotalSection.grandTotal}}" userInput="$15.00" stepKey="checkGrandTotal"/> + <actionGroup ref="AdminOpenOrderCommentsHistoryActionGroup" stepKey="clickOnCommentsHistory"/> + <waitForText selector="{{AdminOrderCommentsTabSection.orderComment}}" userInput="Authorized amount of $15.00. Transaction ID: "{$grabTransactionID}"" stepKey="seeOrderHistoryNotes"/> + </test> +</tests> diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/GuestCheckoutUsingPayPalExpressCheckoutTest.xml b/app/code/Magento/Paypal/Test/Mftf/Test/GuestCheckoutUsingPayPalExpressCheckoutTest.xml new file mode 100644 index 000000000000..a836849a1b5d --- /dev/null +++ b/app/code/Magento/Paypal/Test/Mftf/Test/GuestCheckoutUsingPayPalExpressCheckoutTest.xml @@ -0,0 +1,109 @@ +<?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="GuestCheckoutUsingPayPalExpressCheckoutTest"> + <annotations> + <features value="PayPal"/> + <stories value="Paypal express checkout configuration"/> + <title value="Paypal Express Checkout configuration with valid credentials"/> + <description value="As a customer I want to be able to buy goods using PayPal express with Free Shipping"/> + <severity value="CRITICAL"/> + <testCaseId value="AC-6150"/> + <group value="3rd_party_integration"/> + <group value="paypalExpress"/> + <group value="pr_exclude"/> + </annotations> + <before> + <!-- Simple product is created --> + <createData entity="simpleProductWithoutCategory" stepKey="createProduct"> + <field key="price">10.00</field> + </createData> + <!-- US Customer is created --> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!--Add new tax rates. Go to tax rule page --> + <actionGroup ref="AddNewTaxRuleActionGroup" stepKey="addFirstTaxRuleActionGroup"/> + <fillField stepKey="fillRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="{{TaxRule.name}}"/> + <!-- Adding product rate tax for NY --> + <actionGroup ref="AddNewTaxRateNoZipUIActionGroup" stepKey="addProductTaxRateForCA"> + <argument name="taxCode" value="SimpleTaxTexas"/> + </actionGroup> + <!-- Save Tax Rule --> + <actionGroup ref="ClickSaveButtonActionGroup" stepKey="saveAnotherTaxRule"> + <argument name="message" value="You saved the tax rule."/> + </actionGroup> + <!-- Enable free shipping method --> + <magentoCLI command="config:set {{EnableFreeShippingConfigData.path}} {{EnableFreeShippingConfigData.value}}" stepKey="enableFreeShipping"/> + <!-- Disable flat rate method --> + <magentoCLI command="config:set {{DisableFlatRateConfigData.path}} {{DisableFlatRateConfigData.value}}" stepKey="disableFlatRate"/> + </before> + <after> + <!-- Roll back configuration --> + <magentoCLI command="config:set {{EnableFlatRateConfigData.path}} {{EnableFlatRateConfigData.value}}" stepKey="enableFlatRate"/> + <magentoCLI command="config:set {{DisableFreeShippingConfigData.path}} {{DisableFreeShippingConfigData.value}}" stepKey="disableFreeShipping"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <!-- Go to the tax rule page and delete the row created--> + <actionGroup ref="AdminTaxRuleGridOpenPageActionGroup" stepKey="goToTaxRulesPageA"/> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteRule"> + <argument name="name" value="{{TaxRule.name}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <!-- Deleting Tax zones and rate for Product Tax --> + <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToStoresTaxZonesAndRatesPage"> + <argument name="menuUiId" value="{{AdminMenuStores.dataUiId}}"/> + <argument name="submenuUiId" value="{{AdminMenuStoresTaxZonesAndRates.dataUiId}}"/> + </actionGroup> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteProductTaxRule1"> + <argument name="name" value="{{SimpleTaxTexas.identifier}}-{{SimpleTaxTexas.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <!-- Navigate to StoreFront --> + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToStoreFront"/> + <!-- Add product to cart --> + <actionGroup ref="AddSimpleProductToCartActionGroup" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <actionGroup ref="StorefrontOpenCheckoutPageActionGroup" stepKey="goToCheckout"/> + <!--Fill Shipping Address--> + <actionGroup ref="FillGuestCheckoutShippingAddressFormActionGroup" stepKey="fillShippingAddress"/> + <selectOption selector="{{CheckoutCartSummarySection.stateProvince}}" userInput="Texas" stepKey="fillState"/> + <waitForPageLoad stepKey="waitForShippingPageToLoad"/> + <!-- Select Free Shipping --> + <actionGroup ref="StorefrontSetShippingMethodActionGroup" stepKey="setShippingMethodFreeShipping"> + <argument name="shippingMethodName" value="Free Shipping"/> + </actionGroup> + <!-- Click Next button --> + <actionGroup ref="StorefrontGuestCheckoutProceedToPaymentStepActionGroup" stepKey="clickNext"/> + <!-- Click on PayPal payment radio button --> + <waitForElementClickable selector="{{CheckoutPaymentSection.PayPalPaymentRadio}}" stepKey="waitForPayPalRadioButton"/> + <click selector="{{CheckoutPaymentSection.PayPalPaymentRadio}}" stepKey="selectPaypalPayment"/> + <actionGroup ref="SwitchToPayPalGroupBtnActionGroup" stepKey="clickPayPalBtn"/> + <!-- Login to Paypal in-context and verify order total on paypal page--> + <actionGroup ref="StorefrontLoginToPayPalPaymentAccountTwoStepActionGroup" stepKey="loginToPayPal"/> + <actionGroup ref="StorefrontPaypalSwitchBackToMagentoFromCheckoutPageActionGroup" stepKey="confirmPaymentAndGoBackToMagento"/> + <waitForElementVisible selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="waitForOrderNumberToBeGrabbed"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <waitForText selector="{{CheckoutSuccessMainSection.success}}" userInput="We'll email you an order confirmation with details and tracking info." stepKey="seeSuccessMessage"/> + <!--Assert order in orders grid --> + <!-- Go to order page --> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openFirstOrderPage"> + <argument name="orderId" value="{$grabOrderNumber}"/> + </actionGroup> + <!-- Check status --> + <actionGroup ref="AdminOrderViewCheckStatusActionGroup" stepKey="seeAdminOrderStatus"> + <argument name="status" value="Processing"/> + </actionGroup> + <waitForText selector="{{AdminOrderTotalSection.grandTotal}}" userInput="$10.83" stepKey="checkGrandTotal"/> + <actionGroup ref="AdminOpenOrderCommentsHistoryActionGroup" stepKey="clickOnCommentsHistory"/> + <waitForText selector="{{AdminOrderCommentsTabSection.orderComment}}" userInput="Authorized amount of $10.83." stepKey="seeOrderHistoryNotes"/> + </test> +</tests> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderPaymentInformationSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderPaymentInformationSection.xml index 6c6cb1e9d338..78d7f603e7d4 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderPaymentInformationSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderPaymentInformationSection.xml @@ -5,7 +5,6 @@ * 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="AdminOrderPaymentInformationSection"> @@ -13,5 +12,5 @@ <element name="paymentCurrency" type="text" selector=".order-payment-method .order-payment-currency"/> <element name="paymentAdditional" type="text" selector=".order-payment-method .order-payment-additional"/> <element name="paymentInformationField" type="text" selector="//*[contains(text(),'{{paymentInformationField}}')]/following-sibling::td" parameterized="true"/> - </section> -</sections> \ No newline at end of file + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderTotalSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderTotalSection.xml index 9301bb401835..113916606553 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderTotalSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderTotalSection.xml @@ -21,6 +21,8 @@ <element name="taxRule1" type="text" selector="//table[contains(@class, 'order-subtotal-table')]//td[normalize-space(.)='Canada-GST-5% (5%)']/following-sibling::td//span[@class='price']"/> <element name="taxRule2" type="text" selector="//table[contains(@class, 'order-subtotal-table')]//td[normalize-space(.)='Canada-GST-PST-5% (5%)']/following-sibling::td//span[@class='price']"/> <element name="subTotal1" type="text" selector=".//*[@class='col-subtotal col-price']"/> + <element name="orderTotalPrices" type="text" selector="//strong[text()='{{GrandTotal}}']//ancestor::tr//span[@class = 'price' and text()='{{price}}']" parameterized="true"/> + <element name="subTotalAndShipping" type="text" selector="//td[@class='label' and contains(text(),'{{SubTotal}}')]//parent::tr//span[@class='price' and text()='{{price}}']" parameterized="true"/> <element name="catalogTotalPriceExclTax" type="text" selector="//tbody//tr[@class='col-catalog_price_excl_tax']//span[@class='price' and contains(text(),'{{value}}')]" parameterized="true"/> <element name="catalogTotalPriceInclTax" type="text" selector="//tbody//tr[@class='col-catalog_price_incl_tax']//span[@class='price' and contains(text(),'{{value}}')]" parameterized="true"/> <element name="negotiatedDiscount" type="text" selector="//tbody//tr[@class='col-negotiated_discount']//span[@class='price' and contains(text(),'{{value}}')]" parameterized="true"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWithBaseCurrencyUSDAndDisplayCurrencyEuroTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWithBaseCurrencyUSDAndDisplayCurrencyEuroTest.xml new file mode 100644 index 000000000000..30ed35e7b7eb --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreateCreditMemoWithBaseCurrencyUSDAndDisplayCurrencyEuroTest.xml @@ -0,0 +1,133 @@ +<?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="CreateCreditMemoWithBaseCurrencyUSDAndDisplayCurrencyEuroTest"> + <annotations> + <features value="Order"/> + <stories value="Create Credit Memo"/> + <title value="Create Credit Memo with Base Currency as USD and Display Currency as Euro"/> + <description value="The purpose of this test is to create credit memo with base currency as USD and display currency as Euro and validate the corresponding prices and currency symbols"/> + <severity value="CRITICAL"/> + <testCaseId value="AC-4521"/> + </annotations> + <before> + <!-- Create customer --> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + <!-- Create SimpleProductWithPrice100 --> + <createData entity="SimpleProduct_100" stepKey="createProduct"/> + <!-- Currency Options settings --> + <magentoCLI command="config:set {{SetAllowedCurrenciesConfigForUSD.path}} {{SetAllowedCurrenciesConfigForUSD.value}},{{SetAllowedCurrenciesConfigForEUR.value}}" stepKey="setAllowedCurrencyEURAndUSD"/> + <magentoCLI command="config:set currency/options/default EUR" stepKey="setCurrencyDefaultEUR"/> + <!-- Login as Admin --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!-- Navigate to currency rates page --> + <actionGroup ref="AdminOpenCurrencyRatesPageActionGroup" stepKey="naviagteToCurrencyRatesPage"/> + <!-- Currency Rates (Stores > Currency Rates): 1.000 USD = 0.7067 EUR --> + <actionGroup ref="AdminSetCurrencyRatesActionGroup" stepKey="setCurrencyRates"> + <argument name="firstCurrency" value="USD"/> + <argument name="secondCurrency" value="EUR"/> + <argument name="rate" value="0.7067"/> + </actionGroup> + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> + <argument name="tags" value="config full_page"/> + </actionGroup> + </before> + <after> + <magentoCLI command="config:set {{SetDefaultCurrencyUSDConfig.path}} {{SetDefaultCurrencyUSDConfig.value}}" stepKey="resetDefaultCurrencyBaseBackToUSD"/> + <magentoCLI command="config:set {{SetAllowedCurrenciesConfigForUSD.path}} {{SetAllowedCurrenciesConfigForUSD.value}}" stepKey="resetAllowedCurrencyBaseBackToUSD"/> + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> + <argument name="tags" value="config full_page"/> + </actionGroup> + <!-- Customer log out --> + <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/> + <!-- Delete customer --> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <!-- Delete product --> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <!-- Admin log out --> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <!-- Login as customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> + <argument name="Customer" value="$$createCustomer$$"/> + </actionGroup> + <!-- Navigate To Simple Product Page --> + <actionGroup ref="OpenStoreFrontProductPageActionGroup" stepKey="navigateToSimpleProductPage"> + <argument name="productUrlKey" value="$$createProduct.custom_attributes[url_key]$$"/> + </actionGroup> + <!-- Verify product prices for simple product --> + <actionGroup ref="AssertStorefrontProductPricesActionGroup" stepKey="assertSimpleProductPrices"> + <argument name="productPrice" value="€70.67"/> + <argument name="productFinalPrice" value="€70.67"/> + </actionGroup> + <!-- Add product to cart --> + <actionGroup ref="AddSimpleProductToCartActionGroup" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <actionGroup ref="StorefrontCartPageOpenActionGroup" stepKey="goToShoppingCart"/> + <actionGroup ref="StorefrontClickProceedToCheckoutActionGroup" stepKey="goToCheckout"/> + <!-- verify flat rate €3.53 --> + <waitForText selector="{{CheckoutShippingMethodsSection.price}}" stepKey="seeFlatRate" userInput="€3.53"/> + <!-- click on Next button --> + <actionGroup ref="StorefrontCheckoutClickNextButtonActionGroup" stepKey="clickNext"/> + <!-- verify order summary --> + <actionGroup ref="CheckOrderSummaryInCheckoutActionGroup" stepKey="checkOrderSummary"> + <argument name="subtotal" value="€70.67"/> + <argument name="shippingTotal" value="€3.53"/> + <argument name="shippingMethod" value="Flat Rate - Fixed"/> + <argument name="total" value="€74.20"/> + </actionGroup> + <waitForText userInput="$105.00" selector="{{CheckoutPaymentSection.productChargedFor}}" stepKey="assertProductChargedFor"/> + <!-- Place order --> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="placeOrder"/> + <waitForElement selector="{{CheckoutSuccessMainSection.orderLink}}" stepKey="waitForOrderId"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderLink}}" stepKey="orderId"/> + <!-- Navigate to Sales order page --> + <actionGroup ref="AdminOrdersPageOpenActionGroup" stepKey="navigateToSalesOrderPage"/> + <!-- Open created order --> + <actionGroup ref="AdminOpenOrderByEntityIdActionGroup" stepKey="filterOrdersGridById"> + <argument name="entityId" value="{$orderId}"/> + </actionGroup> + <!-- Submit invoice --> + <actionGroup ref="AdminClickInvoiceButtonOrderViewActionGroup" stepKey="clickOnInvoiceBtn"/> + <actionGroup ref="AdminInvoiceClickSubmitActionGroup" stepKey="clickSubmitInvoice"/> + <waitForElementVisible selector="{{AdminMessagesSection.successMessage}}" stepKey="waitForSuccessMessage"/> + <!-- Click 'Credit Memo' button and create new memo --> + <actionGroup ref="AdminStartToCreateCreditMemoFromOrderPageActionGroup" stepKey="createCreditMemo"/> + <!-- Assert Credit Memo refund prices --> + <actionGroup ref="AssertAdminCreditMemoNewPageTotalsActionGroup" stepKey="assertCreditMemoRefundTotals"> + <argument name="refundShipping" value="5.00"/> + <argument name="adjustmentRefund" value="0.00"/> + <argument name="adjustmentFee" value="0.00"/> + <argument name="subtotalRow" value="$100.00"/> + <argument name="grandTotal" value="$105.00"/> + </actionGroup> + <!-- Assert Grand total and subtotal value --> + <waitForElementVisible selector="{{AdminOrderTotalSection.orderTotalPrices('Grand Total','€74.20')}}" stepKey="waitForGrandTotalValueEURO"/> + <waitForElementVisible selector="{{AdminOrderTotalSection.subTotalAndShipping('Subtotal','€70.67')}}" stepKey="waitForSubTotalValueEURO"/> + <!-- Refund Offline --> + <actionGroup ref="AdminClickRefundOfflineOnCreditMemoDetailPageActionGroup" stepKey="clickRefundOffline"/> + <actionGroup ref="AdminOrdersPageOpenActionGroup" stepKey="navigateToSalesOrderPageAgain"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <waitForElementClickable selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="waitForColumnsDropdownToBeOpened"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="openColumnsDropDown"/> + <!-- Enable to display Total Refunded column and validate currency --> + <checkOption selector="{{AdminProductGridFilterSection.viewColumnOption('Total Refunded')}}" stepKey="showRefundedColumn"/> + <waitForElementClickable selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="waitForColumnsDropdownToBeClickedToClose"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="closeColumnsDropDown"/> + <waitForElement selector="{{AdminProductGridSection.headerNameAndValueOtherCurrency('Grand Total (Base)','105.00')}}" stepKey="waitForGrandTotalBaseValue"/> + <grabTextFrom selector="{{AdminProductGridSection.headerNameAndValueOtherCurrency('Grand Total (Base)','105.00')}}" stepKey="grabGrandTotalBaseValue"/> + <assertEquals stepKey="seeGrandTotalBase"> + <actualResult type="const">$grabGrandTotalBaseValue</actualResult> + <expectedResult type="string">$105.00</expectedResult> + </assertEquals> + <waitForElementVisible selector="{{AdminProductGridSection.headerNameAndValueOtherCurrency('Grand Total (Purchased)','€74.20')}}" stepKey="seeGrandTotalPurchased"/> + <waitForElementVisible selector="{{AdminProductGridSection.headerNameAndValueOtherCurrency('Total Refunded','€74.20')}}" stepKey="seeTotalRefunded"/> + </test> +</tests> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchDefaultConfigWebsiteActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchDefaultConfigWebsiteActionGroup.xml new file mode 100644 index 000000000000..168d76e8b23f --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchDefaultConfigWebsiteActionGroup.xml @@ -0,0 +1,30 @@ +<?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="AdminSwitchDefaultConfigWebsiteActionGroup"> + <!-- Admin switch default config between websites --> + <annotations> + <description>Goes to the Store Configuration page. Click on the default config and switch between the websites.</description> + </annotations> + <arguments> + <argument name="newWebsiteName" type="string"/> + </arguments> + + <amOnPage url="{{AdminB2BConfigPage.url}}" stepKey="goToB2BFeaturesPage3"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + + <click selector="{{AdminConfigSection.defaultConfigButton}}" stepKey="clickDefaultConfigButton"/> + <see selector="{{AdminConfigSection.defaultConfigDropdown}}" userInput="{{newWebsiteName}}" stepKey="seeAssertWebsiteInDefaultConfigDropdown"/> + + <click selector="{{AdminConfigSection.selectWebsiteName(newWebsiteName)}}" stepKey="clickSaveWebsite"/> + <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitForElementVisible"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="acceptMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminAddProductTaxClassConditionalActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminAddProductTaxClassConditionalActionGroup.xml new file mode 100644 index 000000000000..4df93271caa1 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminAddProductTaxClassConditionalActionGroup.xml @@ -0,0 +1,28 @@ +<?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="AdminAddProductTaxClassConditionalActionGroup"> + <annotations> + <description>Adds the provided Product Tax Class to a Tax Rule. Before click on Save check Class Exist or not.</description> + </annotations> + <arguments> + <argument name="prodTaxClassName" type="string"/> + </arguments> + + <!--Click Additional Settings--> + <click stepKey="clickAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <!--Click Product Add New Tax Class Button--> + <click stepKey="clickProdAddNewTaxClassBtn" selector="{{AdminTaxRulesSection.productAddNewTaxClass}}"/> + <!--Fill field--> + <fillField stepKey="fillProdNewTaxClass" selector="{{AdminTaxRulesSection.fieldProdNewTaxClass}}" userInput="{{prodTaxClassName}}"/> + <!-- Save Product tax rate --> + <conditionalClick stepKey="saveProdTaxRate" selector="{{AdminTaxRulesSection.saveProdNewTaxClass}}" dependentSelector="{{AdminTaxRulesSection.selectProductTaxClass('prodTaxClassName')}}" visible="false"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml index f7431b05d513..cbeecc0f2f9d 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml @@ -58,4 +58,53 @@ <data key="zip">78729</data> <data key="rate">0.125</data> </entity> + <entity name="ProductRateTax" type="tax"> + <data key="identifier" unique="suffix">Product Rate</data> + <data key="state">California</data> + <data key="country">United States</data> + <data key="zip">90001</data> + <data key="rate">10</data> + </entity> + <entity name="ShippingRateTax" type="tax"> + <data key="identifier" unique="suffix">Shipping Rate</data> + <data key="state">California</data> + <data key="country">United States</data> + <data key="zip">90001</data> + <data key="rate">5</data> + </entity> + <entity name="ProductRateTaxNY" type="tax"> + <data key="identifier" unique="suffix">Product Rate NY</data> + <data key="state">New York</data> + <data key="country">United States</data> + <data key="zip">10001</data> + <data key="rate">20</data> + </entity> + <entity name="ShippingRateTaxNY" type="tax"> + <data key="identifier" unique="suffix">Shipping Rate NY</data> + <data key="state">New York</data> + <data key="country">United States</data> + <data key="zip">10001</data> + <data key="rate">10</data> + </entity> + <entity name="SimpleTaxTexas" type="tax"> + <data key="identifier" unique="suffix" >Texas</data> + <data key="state">Texas</data> + <data key="country">United States</data> + <data key="zip">*</data> + <data key="rate">8.3</data> + </entity> + <entity name="ShippingRateTaxCA" type="tax"> + <data key="identifier" unique="suffix">Shipping Rate</data> + <data key="state">California</data> + <data key="country">United States</data> + <data key="zip">*</data> + <data key="rate">5</data> + </entity> + <entity name="ProductRateTaxCA" type="tax"> + <data key="identifier" unique="suffix">Product Rate</data> + <data key="state">California</data> + <data key="country">United States</data> + <data key="zip">*</data> + <data key="rate">4</data> + </entity> </entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml index 4f2ebc1d18ee..aae0921b72fe 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml @@ -152,4 +152,16 @@ <var key="tax_rate_ids" entityType="taxRate" entityKey="id"/> <data key="calculate_subtotal">false</data> </entity> + <entity name="ProductTax" type="taxRule"> + <data key="name" unique="suffix">ProductTax</data> + </entity> + <entity name="ProductShipping" type="taxRule"> + <data key="name" unique="suffix">ProductShipping</data> + </entity> + <entity name="ShippingTax" type="taxRule"> + <data key="name" unique="suffix">ShippingTax</data> + </entity> + <entity name="ShippingGood" type="taxRule"> + <data key="name" unique="suffix">ShippingGood</data> + </entity> </entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index e6182714b108..9a8a34eaf861 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -54,6 +54,7 @@ <element name="dropdownDisplayZeroTaxCart" type="checkbox" selector="#row_tax_cart_display_zero_tax select"/> <element name="ordersInvoicesCreditSales" type="block" selector="#tax_sales_display-head" timeout="30"/> + <element name="taxSalesDisplayHeadOpen" type="block" selector="#tax_sales_display-head.open" timeout="30"/> <element name="systemValueIncludeTaxTotalSales" type="checkbox" selector="#row_tax_sales_display_grandtotal input[type='checkbox']"/> <element name="dropdownIncludeTaxTotalSales" type="checkbox" selector="#row_tax_sales_display_grandtotal select"/> <element name="systemValueDisplayTaxSummarySales" type="checkbox" selector="#row_tax_sales_display_full_summary input[type='checkbox']"/> @@ -68,6 +69,14 @@ <element name="dropdownIncludingFPTAndFPTDescription" type="checkbox" selector="#row_tax_weee_display_list select"/> <element name="systemValueApplyTaxToFpt" type="checkbox" selector="#row_tax_weee_apply_vat input[type='checkbox']"/> <element name="dropdownApplyTaxToFpt" type="checkbox" selector="#row_tax_weee_apply_vat select"/> + <element name="orderInvoiceSubtotalInherit" type="checkbox" selector="#tax_sales_display_subtotal_inherit"/> + <element name="orderInvoiceDisplaySubtotal" type="select" selector="#tax_sales_display_subtotal"/> + <element name="taxSalesDisplaySubtotal" type="checkbox" selector="#tax_sales_display_grandtotal_inherit"/> + <element name="taxSalesDisplayGrandTotal" type="select" selector="#tax_sales_display_grandtotal"/> + <element name="taxSalesDisplayFullSummaryInherit" type="checkbox" selector="#tax_sales_display_full_summary_inherit"/> + <element name="taxSalesDisplayFullSummary" type="select" selector="#tax_sales_display_full_summary"/> + <element name="taxSalesDisplayZeroTaxInherit" type="checkbox" selector="#tax_sales_display_zero_tax_inherit"/> + <element name="taxSalesDisplayZeroTax" type="select" selector="#tax_sales_display_zero_tax"/> <element name="taxClassesCondition" type="block" selector="//a[@id='tax_classes-head' and @class='open']" timeout="30"/> <element name="useSystemValue" type="checkbox" selector="#tax_classes_default_product_tax_class_inherit"/> diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserViaCurlActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserViaCurlActionGroup.xml index 66013b4d23a2..e1a5f66294c0 100644 --- a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserViaCurlActionGroup.xml +++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminDeleteUserViaCurlActionGroup.xml @@ -14,12 +14,13 @@ </arguments> <amOnPage stepKey="amOnAdminUsersPage" url="{{AdminUsersPage.url}}"/> <waitForPageLoad stepKey="waitForAdminUserPageLoad"/> + <waitForElementClickable selector="{{AdminLegacyDataGridFilterSection.clear}}" stepKey="WaitForresetFiltersElementToBeClickable"/> <click selector="{{AdminLegacyDataGridFilterSection.clear}}" stepKey="resetFilters" /> <waitForPageLoad stepKey="waitForFiltersToReset" /> <waitForElementVisible selector="{{AdminLegacyDataGridTableSection.columnTemplateStrict(user.username, 'user_id')}}" stepKey="waitForUserIdVisible" /> <scrollTo selector="{{AdminLegacyDataGridTableSection.columnTemplateStrict(user.username, 'user_id')}}" stepKey="scrollToUserId" /> + <waitForElementVisible selector="{{AdminLegacyDataGridTableSection.columnTemplateStrict(user.username, 'user_id')}}" stepKey="waitForUserIdVisibleBeforeElementIsGrabbed" /> <grabTextFrom selector="{{AdminLegacyDataGridTableSection.columnTemplateStrict(user.username, 'user_id')}}" stepKey="userId" /> - <createData entity="deleteUser" stepKey="deleteUser"> <field key="user_id">{$userId}</field> <field key="current_password">{{adminPassword}}</field> diff --git a/app/etc/di.xml b/app/etc/di.xml index eed765920f95..7ffe8e749b20 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -94,6 +94,7 @@ <preference for="Magento\Framework\Stdlib\Cookie\CookieScopeInterface" type="Magento\Framework\Stdlib\Cookie\CookieScope" /> <preference for="Magento\Framework\Stdlib\Cookie\CookieReaderInterface" type="Magento\Framework\Stdlib\Cookie\PhpCookieReader" /> <preference for="Magento\Framework\Stdlib\CookieManagerInterface" type="Magento\Framework\Stdlib\Cookie\PhpCookieManager" /> + <preference for="Magento\Framework\Stdlib\CookieDisablerInterface" type="Magento\Framework\Stdlib\Cookie\PhpCookieDisabler" /> <preference for="Magento\Framework\TranslateInterface" type="Magento\Framework\Translate" /> <preference for="Magento\Framework\Config\ScopeListInterface" type="interceptionConfigScope" /> <preference for="Magento\Framework\View\Design\Theme\Label\ListInterface" type="Magento\Theme\Model\ResourceModel\Theme\Collection" /> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/GraphQl/GraphQlSessionTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/GraphQl/GraphQlSessionTest.php index 7c37ea001380..f5b811a63cbd 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/GraphQl/GraphQlSessionTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/GraphQl/GraphQlSessionTest.php @@ -48,6 +48,10 @@ public function setUp(): void /** * Test for checking if graphQL query sets session cookies * + * Note: The reason why the first response doesn't have cookies, but the subsequent responses do is + * because Magento/Framework/App/PageCache/Kernel.php removes Set-Cookie headers when the response has a + * public Cache-Control. This test asserts that behaviour. + * * @magentoApiDataFixture Magento/Catalog/_files/categories.php * @magentoConfigFixture graphql/session/disable 0 */ @@ -71,8 +75,7 @@ public function testCheckSessionCookieWithGetCategoryList(): void $result = $this->graphQlClient->getWithResponseHeaders($query, [], '', [], true); $this->assertEmpty($result['cookies']); // perform secondary request after cookies have been flushed - $result = $this->graphQlClient->getWithResponseHeaders($query, [], '', []); - + $result = $this->graphQlClient->getWithResponseHeaders($query, [], '', [], true); // may have other cookies than session $this->assertNotEmpty($result['cookies']); $this->assertAnyCookieMatchesRegex('/PHPSESSID=[a-z0-9]+;/', $result['cookies']); @@ -280,4 +283,46 @@ private function assertNoCookiesMatchRegex(string $pattern, array $cookies): voi } $this->assertTrue($result, 'Failed assertion. At least one cookie in the array matches pattern: ' . $pattern); } + + /** + * Tests that Magento\Customer\Model\Session works properly when graphql/session/disable=0 + * + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoConfigFixture graphql/session/disable 0 + */ + public function testCustomerCanQueryOwnEmailUsingSession() : void + { + $query = '{customer{email}}'; + $result = $this->graphQlClient->postWithResponseHeaders($query, [], '', $this->getAuthHeaders(), true); + // cookies are never empty and session is restarted for the authorized customer regardless current session + $this->assertNotEmpty($result['cookies']); + $this->assertAnyCookieMatchesRegex('/PHPSESSID=[a-z0-9]+;/', $result['cookies']); + $this->assertEquals('customer@example.com', $result['body']['customer']['email'] ?? ''); + $result = $this->graphQlClient->postWithResponseHeaders($query, [], '', $this->getAuthHeaders()); + // cookies are never empty and session is restarted for the authorized customer + // regardless current session and missing flush + $this->assertNotEmpty($result['cookies']); + $this->assertAnyCookieMatchesRegex('/PHPSESSID=[a-z0-9]+;/', $result['cookies']); + $this->assertEquals('customer@example.com', $result['body']['customer']['email'] ?? ''); + /* Note: This third request is the actual one that tests that the session cookie is properly used. + * This time we don't send the Authorization header and rely on Cookie header instead. + * Because of bug in postWithResponseHeaders's $flushCookies parameter not being properly used, + * We have to manually set cookie header ourselves. :-( + */ + $cookiesToSend = ''; + foreach ($result['cookies'] as $cookie) { + preg_match('/^([^;]*);/', $cookie, $matches); + if (!strlen($matches[1] ?? '')) { + continue; + } + if (!empty($cookiesToSend)) { + $cookiesToSend .= '; '; + } + $cookiesToSend .= $matches[1]; + } + $result = $this->graphQlClient->postWithResponseHeaders($query, [], '', ['Cookie: ' . $cookiesToSend]); + $this->assertNotEmpty($result['cookies']); + $this->assertAnyCookieMatchesRegex('/PHPSESSID=[a-z0-9]+;/', $result['cookies']); + $this->assertEquals('customer@example.com', $result['body']['customer']['email'] ?? ''); + } } diff --git a/lib/internal/Magento/Framework/App/PageCache/Kernel.php b/lib/internal/Magento/Framework/App/PageCache/Kernel.php index c4d88f031a51..d6a9a249ec38 100644 --- a/lib/internal/Magento/Framework/App/PageCache/Kernel.php +++ b/lib/internal/Magento/Framework/App/PageCache/Kernel.php @@ -7,6 +7,7 @@ use Magento\Framework\App\State as AppState; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Stdlib\CookieDisablerInterface; /** * Builtin cache processor @@ -68,6 +69,9 @@ class Kernel */ private $identifierForSave; + // phpcs:disable Magento2.Commenting.ClassPropertyPHPDocFormatting + private readonly CookieDisablerInterface $cookieDisabler; + /** * @param Cache $cache * @param \Magento\Framework\App\PageCache\IdentifierInterface $identifier @@ -79,6 +83,7 @@ class Kernel * @param AppState|null $state * @param \Magento\PageCache\Model\Cache\Type|null $fullPageCache * @param \Magento\Framework\App\PageCache\IdentifierInterface|null $identifierForSave + * @param CookieDisablerInterface|null $cookieDisabler * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -91,7 +96,8 @@ public function __construct( \Magento\Framework\Serialize\SerializerInterface $serializer = null, AppState $state = null, \Magento\PageCache\Model\Cache\Type $fullPageCache = null, - \Magento\Framework\App\PageCache\IdentifierInterface $identifierForSave = null + \Magento\Framework\App\PageCache\IdentifierInterface $identifierForSave = null, + ?CookieDisablerInterface $cookieDisabler = null, ) { $this->cache = $cache; $this->identifier = $identifier; @@ -113,6 +119,7 @@ public function __construct( $this->identifierForSave = $identifierForSave ?? ObjectManager::getInstance()->get( \Magento\Framework\App\PageCache\IdentifierInterface::class ); + $this->cookieDisabler = $cookieDisabler ?? ObjectManager::getInstance()->get(CookieDisablerInterface::class); } /** @@ -163,9 +170,7 @@ public function process(\Magento\Framework\App\Response\Http $response) if ($this->state->getMode() != AppState::MODE_DEVELOPER) { $response->clearHeader('X-Magento-Tags'); } - if (!headers_sent()) { - header_remove('Set-Cookie'); - } + $this->cookieDisabler->setCookiesDisabled(true); $this->fullPageCache->save( $this->serializer->serialize($this->getPreparedData($response)), diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php b/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php index 2dc0a67e0f07..58f256ebb0e2 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php @@ -9,6 +9,7 @@ use Cm\RedisSession\Handler\LoggerInterface; use Cm\RedisSession\ConnectionFailedException; use Cm\RedisSession\ConcurrentConnectionsExceededException; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\SessionException; use Magento\Framework\Phrase; use Magento\Framework\Filesystem; @@ -82,7 +83,7 @@ public function read($sessionId) try { $result = $this->getConnection()->read($sessionId); } catch (ConcurrentConnectionsExceededException $e) { - require $this->filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/503.php'); + throw new LocalizedException(__("Redis session exceeded concurrent connections"), $e); } return $result; diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php index f79f0900c2c2..ce381bb22782 100644 --- a/lib/internal/Magento/Framework/Session/SessionManager.php +++ b/lib/internal/Magento/Framework/Session/SessionManager.php @@ -638,13 +638,6 @@ private function initIniOptions() */ public function _resetState(): void { - if (session_status() === PHP_SESSION_ACTIVE) { - session_write_close(); - session_id(''); - } - session_name('PHPSESSID'); - session_unset(); static::$urlHostCache = []; - $_SESSION = []; } } diff --git a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieDisabler.php b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieDisabler.php new file mode 100644 index 000000000000..76cd5848458e --- /dev/null +++ b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieDisabler.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Stdlib\Cookie; + +use Magento\Framework\Stdlib\CookieDisablerInterface; + +/** + * Disables sending the cookies that are currently set. + */ +class PhpCookieDisabler implements CookieDisablerInterface +{ + /** + * @inheritDoc + */ + public function setCookiesDisabled(bool $disabled) : void + { + if ($disabled && !headers_sent()) { + header_remove('Set-Cookie'); + } + } +} diff --git a/lib/internal/Magento/Framework/Stdlib/CookieDisablerInterface.php b/lib/internal/Magento/Framework/Stdlib/CookieDisablerInterface.php new file mode 100644 index 000000000000..efc9795c4e4e --- /dev/null +++ b/lib/internal/Magento/Framework/Stdlib/CookieDisablerInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Stdlib; + +/** + * This interface is for when you need to disable all cookies from being sent in the HTTP response + */ +interface CookieDisablerInterface +{ + /** + * Set Cookies Disabled. If true, cookies won't be sent. + * + * @param bool $disabled + * @return void + */ + public function setCookiesDisabled(bool $disabled) : void; +} diff --git a/pub/errors/default/page.phtml b/pub/errors/default/page.phtml index 179dab069fe5..e7a03fb3744c 100644 --- a/pub/errors/default/page.phtml +++ b/pub/errors/default/page.phtml @@ -19,7 +19,7 @@ </head> <body> <main class="page-main"> - <?php require_once $contentTemplate; ?> + <?php require $contentTemplate; ?> </main> </body> </html> diff --git a/pub/errors/processor.php b/pub/errors/processor.php index ee349ef156f6..5e4cd135d86c 100644 --- a/pub/errors/processor.php +++ b/pub/errors/processor.php @@ -188,7 +188,6 @@ public function __construct( $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); $this->escaper = $escaper ?: ObjectManager::getInstance()->get(Escaper::class); $this->documentRoot = $documentRoot ?? ObjectManager::getInstance()->get(DocumentRoot::class); - if (!empty($_SERVER['SCRIPT_NAME'])) { if (in_array(basename($_SERVER['SCRIPT_NAME'], '.php'), ['404', '503', 'report'])) { $this->_scriptName = dirname($_SERVER['SCRIPT_NAME']); @@ -196,10 +195,8 @@ public function __construct( $this->_scriptName = $_SERVER['SCRIPT_NAME']; } } - $this->_indexDir = $this->_getIndexDir(); $this->_root = is_dir($this->_indexDir . 'app'); - $this->_prepareConfig(); if (isset($_GET['skin'])) { $this->_setSkin($_GET['skin']); @@ -207,6 +204,7 @@ public function __construct( if (isset($_GET['id'])) { $this->loadReport($_GET['id']); } + $response->setMetadata("NotCacheable", true); } /** @@ -449,7 +447,7 @@ protected function _renderPage($template) $html = ''; if ($baseTemplate && $contentTemplate) { ob_start(); - require_once $baseTemplate; + require $baseTemplate; $html = ob_get_clean(); } return $html; diff --git a/pub/errors/processorFactory.php b/pub/errors/processorFactory.php index 11320ec6eb4c..c519a6d36922 100644 --- a/pub/errors/processorFactory.php +++ b/pub/errors/processorFactory.php @@ -3,10 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +// phpcs:disable PSR1.Files.SideEffects namespace Magento\Framework\Error; +// phpcs:ignore Magento2.Functions.DiscouragedFunction,Magento2.Security.IncludeFile require_once realpath(__DIR__) . '/../../app/bootstrap.php'; -require_once 'processor.php'; +require_once 'processor.php'; // phpcs:ignore Magento2.Security.IncludeFile +use Magento\Framework\App\ObjectManager as AppObjectManager; /** * Error processor factory @@ -20,9 +23,15 @@ class ProcessorFactory */ public function createProcessor() { - $objectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); - $objectManager = $objectManagerFactory->create($_SERVER); - $response = $objectManager->create(\Magento\Framework\App\Response\Http::class); - return new Processor($response); + try { + $objectManager = AppObjectManager::getInstance(); + return $objectManager->create(Processor::class); + } catch (\RuntimeException $exception) { + // phpcs:ignore Magento2.Security.Superglobal + $objectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); + $objectManager = $objectManagerFactory->create($_SERVER); // phpcs:ignore Magento2.Security.Superglobal + $response = $objectManager->create(\Magento\Framework\App\Response\Http::class); + return new Processor($response); + } } } diff --git a/pub/get.php b/pub/get.php index fb619a0dfa51..ac9b50108584 100644 --- a/pub/get.php +++ b/pub/get.php @@ -62,13 +62,13 @@ $fileRelativePath = str_replace(rtrim($mediaDirectory, '/') . '/', '', $fileAbsolutePath); if (!$isAllowed($fileRelativePath, $allowedResources)) { - require_once 'errors/404.php'; + require 'errors/404.php'; exit; } if (is_readable($fileAbsolutePath)) { if (is_dir($fileAbsolutePath)) { - require_once 'errors/404.php'; + require 'errors/404.php'; exit; }