Magento Functional Testing Framework. What in the world is that?
Introduction
Magento Functional Testing Framework (MFTF) is an open-source testing framework. It was developed & released by the Magento team for its Magento ecosystem. This framework is used to perform automated end-to-end functional testing.
The MFTF is used to write XML test cases. These test cases are auto-converted into PHP scripts and tested in Codeception, Selenium, or Allure. These are the tools MFTF employs. In this way, writing test cases becomes simpler. The framework provides a set of other functions and complex test cases. The existing tests can be used as parent templates for writing new tests.
However, you need to learn how to configure MFTF correctly before using the whole range of its functions.
Configuration
Make sure that you have the following software installed and configured in your development environment:
- PHP version supported by the Magento instance under test;
- Composer 1.3 or later;
- Java 1.8 or later;
- Selenium Server Standalone 3.1 or later;
- ChromeDriver 2.33 or later corresponds to your browser’s version.
Here’s where you can learn how to install software and get started: and configurationTo run Magento CLI in tests, add the following location block to the Nginx configuration file in the Magento root directory before all location blocks:
location ~* ^/dev/tests/acceptance/utils($|/) {
root $MAGE_ROOT;
location ~ ^/dev/tests/acceptance/utils/command.php {
fastcgi_pass fastcgi_backend;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Use the command below to check the CLI command configuration:
vendor/bin/mftf doctor
The main file with MFTF configuration is dev/tests/acceptance/.env. An example of all configurations is found at vendor/magento/magento2-functional-testing-framework/etc/config/.env.example. Information about parameters is in the DevDocs.
There is an example of my .env:
MAGENTO_BASE_URL=http://magento.loc/
MAGENTO_BACKEND_NAME=admin_rdl4mg
MAGENTO_ADMIN_USERNAME=admin
MAGENTO_ADMIN_PASSWORD=admin123
SELENIUM_CLOSE_ALL_SESSIONS=true
BROWSER=chrome
BROWSER_LOG_BLOCKLIST=other
ELASTICSEARCH_VERSION=7
Run test
If you did everything right according to DevDocs, you can run the first existing Magento test. You should have already downloaded Selenium and ChromeDriver by now and stored them in a folder on your computer. You can run the Selenium server with the command
java -Dwebdriver.chrome.driver={chromedriver location} -jar {selenium location}.
An example:
java -Dwebdriver.chrome.driver=/usr/local/bin/chromedriver -jar selenium-server-standalone-3.141.59.jar
12:49:45.416 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358
12:49:45.467 INFO [GridLauncherV3.lambda$buildLaunchers$3] - Launching a standalone Selenium Server on port 4444
2022-01-17 12:49:45.500:INFO::main: Logging initialized @306ms to org.seleniumhq.jetty9.util.log.StdErrLog
12:49:45.648 INFO [WebDriverServlet.<init>] - Initialising WebDriverServlet
12:49:45.700 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444
The selenium server is running. Now, it’s time to use Magento commands to run functional tests by name or group name. See the following example of a test run and response:
vendor/bin/mftf run:test AdminLoginSuccessfulTest
Generate Tests Command Run
Codeception PHP Testing Framework v4.1.28
Powered by PHPUnit 9.2.6 by Sebastian Bergmann and contributors.
Magento\FunctionalTestingFramework.functional Tests (1) ------------------------
Modules: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver, \Magento\FunctionalTestingFramework\Module\MagentoSequence, \Magento\FunctionalTestingFramework\Module\MagentoAssert, \Magento\FunctionalTestingFramework\Module\MagentoActionProxies, Asserts, \Magento\FunctionalTestingFramework\Helper\HelperContainer
--------------------------------------------------------------------------------
AdminLoginSuccessfulTestCest: Admin login successful test
Signature: Magento\AcceptanceTest\_default\Backend\AdminLoginSuccessfulTestCest:AdminLoginSuccessfulTest
Test: tests/functional/Magento/_generated/default/AdminLoginSuccessfulTestCest.php:AdminLoginSuccessfulTest
Scenario --
[loginAsAdmin] AdminLoginActionGroup
[navigateToAdmin] am on page "/admin_rdl4mg/admin"
[fillUsername] fill field "#username","admin"
[fillPassword] fill field "#login","admin123"
[clickLogin] click ".actions .action-primary"
[clickLoginWaitForPageLoad] wait for page load 30
[clickDontAllowButtonIfVisible] conditional click ".modal-popup .action-secondary",".modal-popup .action-secondary",true
[closeAdminNotification] close admin notification
[assertLoggedIn] AssertAdminSuccessLoginActionGroup
[waitForAdminAccountTextVisible] wait for element visible ".page-header .admin-user-account-text",30
[assertAdminAccountTextElement] see element ".page-header .admin-user-account-text"
[logoutFromAdmin] AdminLogoutActionGroup
[amOnLogoutPage] am on page "/admin_rdl4mg/admin/auth/logout/"
PASSED
--------------------------------------------------------------------------------
Time: 00:07.329, Memory: 20.00 MB
OK (1 test, 1 assertion)
Our custom functional test
Read the following DevDocs articles to better understand the information and logic used for creating the test:
All the XML instructions for the functional test are located on our module:
app/code/<vendor_name>/<module_name>/Test/Mftf/
Create an XML file:app/code/ItDelight/FunctionalTest/Test/Mftf/Test/StorefrontExampleTest.xml
<?xml version="1.0" encoding="UTF-8"?>
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="StorefrontExampleTest">
<annotations>
<features value="Test Module"/>
<stories value="Create customer and product"/>
<title value="Example Test"/>
<description value="Functional test for introduction"/>
<severity value="CRITICAL"/>
<group value="Test"/>
</annotations>
</test>
</tests>
Read more information about annotations.
The XML instruction has tags <before> and <after>. They allow adding configuration before the start of the test and clearing extra data after the end of the test.1.
In these tags, you can use CLI commands and change the store configuration needed for different test cases.
Let’s create a customer entity. The information about entities is defined in XML, which is located in app/code/ItDelight/FunctionalTest/Test/Mftf/Data/. More information about Data.
We can extend the customer entity from the Simple_US_Customer definite in the vendor/magento/module-customer/Test/Mftf/Data/CustomerData.xml and change firstname, lastname, and fullname.
As a result, we get the next app/code/ItDelight/FunctionalTest/Test/Mftf/Data/CustomerData.xml
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
<entity name="Dev_Customer" extends="Simple_US_Customer">
<data key="firstname">Alex</data>
<data key="lastname">Dev</data>
<data key="fullname">Alex Dev</data>
</entity>
</entities>
Next, add a product entity with a custom url_key and name. The url_key is a custom attribute, and we have to create an entity for this attribute: app/code/ItDelight/FunctionalTest/Test/Mftf/Data/CustomAttributeData.xml
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
<entity name="CustomAttributeDevUrlKey" type="custom_attribute">
<data key="attribute_code">url_key</data>
<data key="value" unique="suffix">example</data>
</entity>
</entities>
Now we can use the entity CustomAttributeDevUrlKey for the custom product entity. Extend our product from the existing product entity (vendor/magento/module-catalog/Test/Mftf/Data/ProductData.xml), change the product name to our custom name, and URL key with a dynamic suffix to the URL (parameter unique=”suffix”). More information about the product entity by link.
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
<entity name="DevProduct" type="product" extends="SimpleProduct2">
<data key="name" unique="suffix">devProduct</data>
<requiredEntity type="custom_attribute">CustomAttributeDevUrlKey</requiredEntity>
</entity>
</entities>
According to the created entities, let’s add them to the tag <before> on our test. Use tab <createData> to do that ( ).
app/code/ItDelight/FunctionalTest/Test/Mftf/Test/StorefrontExampleTest.xml
[...]
</annotations>
<before>
<createData entity="DevProduct" stepKey="createSimpleProduct"/>
<createData entity="Dev_Customer" stepKey="createCustomer"/>
</before>
</test>
</tests>
When creating entities, we have to run indexation. We used the tag <magentoCLI> for that. It allows running CLI commands during a functional test. Let’s use tag <magentoCLI> to enable a clear shopping cart configuration and clear full_page and config cache.
[...]
<before>
<createData entity="DevProduct" stepKey="createSimpleProduct"/>
<createData entity="Dev_Customer" stepKey="createCustomer"/>
<magentoCLI command="config:set checkout/cart/enable_clear_shopping_cart 1" stepKey="enableClearShoppingCart"/>
<magentoCLI command="indexer:reindex" stepKey="runReindex"/>
<magentoCLI command="cache:clean" arguments="full_page config" stepKey="cleanSpecifiedCache"/>
</before>
</test>
</tests>
After finishing the test, we return Magento to the default state. To remove all created entities and return the configuration, we use the tag instruction <after> with a tag <deleteData> (https://devdocs.magento.com/mftf/docs/test/actions.html#deletedata) for entities.
[...]
</before>
<after>
<deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/>
<deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/>
<magentoCLI command="config:set checkout/cart/enable_clear_shopping_cart 0" stepKey="disableClearShoppingCart"/>
<magentoCLI command="indexer:reindex" stepKey="runReindex"/>
<magentoCLI command="cache:clean" arguments="full_page config" stepKey="cleanSpecifiedCache"/>
</after>
</test>
</tests>
At this point, we can check our test for errors.
vendor/bin/mftf run:test StorefrontExampleTest
Generate Tests Command Run
Codeception PHP Testing Framework v4.1.28
Powered by PHPUnit 9.2.6 by Sebastian Bergmann and contributors.
Magento\FunctionalTestingFramework.functional Tests (1) ------------------------
Modules: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver, \Magento\FunctionalTestingFramework\Module\MagentoSequence, \Magento\FunctionalTestingFramework\Module\MagentoAssert, \Magento\FunctionalTestingFramework\Module\MagentoActionProxies, Asserts, \Magento\FunctionalTestingFramework\Helper\HelperContainer
--------------------------------------------------------------------------------
StorefrontExampleTestCest: Storefront example test
Signature: Magento\AcceptanceTest\_default\Backend\StorefrontExampleTestCest:StorefrontExampleTest
Test: tests/functional/Magento/_generated/default/StorefrontExampleTestCest.php:StorefrontExampleTest
Scenario --
[createSimpleProduct] create entity "createSimpleProduct","hook","DevProduct",[],[]
[createCustomer] create entity "createCustomer","hook","Dev_Customer",[],[]
[enableClearShoppingCart] magento cli "config:set checkout/cart/enable_clear_shopping_cart 1",60
Value was saved.
[runReindex] magento cli "indexer:reindex",60
Design Config Grid index has been rebuilt successfully in 00:00:00
Customer Grid index has been rebuilt successfully in 00:00:00
Category Products ind
[cleanSpecifiedCache] magento cli "cache:clean",60,"full_page config"
Cleaned cache types:
config
full_page
[deleteProduct] delete entity "createSimpleProduct","hook"
[deleteCustomer] delete entity "createCustomer","hook"
[disableClearShoppingCart] magento cli "config:set checkout/cart/enable_clear_shopping_cart 0",60
Value was saved.
[runReindex] magento cli "indexer:reindex",60
Design Config Grid index has been rebuilt successfully in 00:00:00
Customer Grid index has been rebuilt successfully in 00:00:00
Category Products ind
[cleanSpecifiedCache] magento cli "cache:clean",60,"full_page config"
Cleaned cache types:
config
full_page
PASSED
--------------------------------------------------------------------------------
Time: 00:29.952, Memory: 46.00 MB
If everything is as it is supposed to be, we can continue.
Now it’s time to add instructions that allow login-created customers from the storefront.
Use the tag <amOnPage> to go to the account login page.
We have to use the tag <waitForPageLoad>, which allows us to wait for the page to load.
A tag <fillField> allows filling an input field with a text field by JS or XPath selector.
When we fill in all inputs in a login form, we can use the tag <click> to submit the login form.
Wait for the page to load before checking the page title with the tag <see>
The $$persistedCreateDataKey.field$$ syntax is used to work with created entities createSimpleProduct, and createCustomer.
[...]
</after>
<amOnPage url="/customer/account/login/" stepKey="amOnSignInPage"/>
<waitForPageLoad time="30" stepKey="waitPageFullyLoaded"/>
<waitForElementVisible selector="#email" stepKey="waitFormAppears"/>
<fillField userInput="$$createCustomer.email$$" selector="#email" stepKey="fillEmail"/>
<fillField userInput="$$createCustomer.password$$" selector="#pass" stepKey="fillPassword"/>
<click selector="#send2" stepKey="clickSignInAccountButton"/>
<waitForPageLoad stepKey="waitForCustomerLoggedIn"/>
<see selector="div.page-title-wrapper > h1 > span" userInput="My Account" stepKey="seeAccountTitle"/>
</test>
</tests>
We can refactor this code to better understand this instruction. Firstly, move all selectors to a new Section. We will create two sections: app/code/ItDelight/FunctionalTest/Test/Mftf/Section/StorefrontCustomerLoginSection.xml
<?xml version="1.0" encoding="UTF-8"?>
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
<section name="StorefrontCustomerLoginSection">
<element name="emailField" type="input" selector="#email"/>
<element name="passwordField" type="input" selector="#pass"/>
<element name="signInAccountButton" type="button" selector="#send2" timeout="30"/>
</section>
</sections>
and app/code/ItDelight/FunctionalTest/Test/Mftf/Section/StorefrontCustomerAccountSection.xml
<?xml version="1.0" encoding="UTF-8"?>
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
<section name="StorefrontCustomerAccountSection">
<element name="pageTitle" type="text" selector="div.page-title-wrapper > h1 > span"/>
</section>
</sections>
Then, create an XML page for the account login page: app/code/ItDelight/FunctionalTest/Test/Mftf/Page/StorefrontCustomerLoginPage.xml
<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
<page name="StorefrontCustomerLoginPage" url="/customer/account/login/" area="storefront" module="ItDelight_FunctionalTest">
<section name="StorefrontCustomerLoginSection" />
</page>
</pages>
Move the page title to app/code/ItDelight/FunctionalTest/Test/Mftf/Data/PageData.xml
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
<entity name="AccountPageData">
<data key="title">My Account</data>
</entity>
</entities>
The result: app/code/ItDelight/FunctionalTest/Test/Mftf/Test/StorefrontExampleTest.xml
[...]
</after>
<amOnPage url="{{StorefrontCustomerLoginPage.url}}" stepKey="amOnSignInPage"/>
<waitForPageLoad time="30" stepKey="waitPageFullyLoaded"/>
<waitForElementVisible selector="{{StorefrontCustomerLoginSection.emailField}}" stepKey="waitFormAppears"/>
<fillField userInput="$$createCustomer.email$$" selector="{{StorefrontCustomerLoginSection.emailField}}" stepKey="fillEmail"/>
<fillField userInput="$$createCustomer.password$$" selector="{{StorefrontCustomerLoginSection.passwordField}}" stepKey="fillPassword"/>
<click selector="{{StorefrontCustomerLoginSection.signInAccountButton}}" stepKey="clickSignInAccountButton"/>
<waitForPageLoad stepKey="waitForCustomerLoggedIn"/>
<see selector="{{StorefrontCustomerAccountSection.pageTitle}}" userInput="{{AccountPageData.title}}" stepKey="seeAccountTitle"/>
</test>
</tests>
You can use this test case in the other tests. That’s why we can move this instruction to the action group with the customer entity argument
app/code/ItDelight/FunctionalTest/Test/Mftf/ActionGroup/CustomerLoginExampleActionGroup.xml
<?xml version="1.0" encoding="UTF-8"?>
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
<actionGroup name="CustomerLoginExampleActionGroup">
<annotations>
<description>Goes to the customer login page. Logs in using the provided Customer.</description>
</annotations>
<arguments>
<argument name="Customer"/>
</arguments>
<amOnPage url="{{StorefrontCustomerLoginPage.url}}" stepKey="amOnSignInPage"/>
<waitForPageLoad time="30" stepKey="waitPageFullyLoaded"/>
<waitForElementVisible selector="{{StorefrontCustomerLoginSection.emailField}}" stepKey="waitFormAppears"/>
<fillField userInput="{{Customer.email}}" selector="{{StorefrontCustomerLoginSection.emailField}}" stepKey="fillEmail"/>
<fillField userInput="{{Customer.password}}" selector="{{StorefrontCustomerLoginSection.passwordField}}" stepKey="fillPassword"/>
<click selector="{{StorefrontCustomerLoginSection.signInAccountButton}}" stepKey="clickSignInAccountButton"/>
<waitForPageLoad stepKey="waitForCustomerLoggedIn"/>
<see selector="{{StorefrontCustomerAccountSection.pageTitle}}" userInput="{{AccountPageData.title}}" stepKey="seeAccountTitle"/>
</actionGroup>
</actionGroups>
Finally, we get to this form: app/code/ItDelight/FunctionalTest/Test/Mftf/Test/StorefrontExampleTest.xml
[...]
</after>
<actionGroup ref="CustomerLoginExampleActionGroup" stepKey="loginToStorefront">
<argument name="Customer" value="$$createCustomer$$"/>
</actionGroup>
</test>
</tests>
In this step, we will work with the product entity. Create a new action group with a description and set an argument createSimpleProduct entity from our test.
app/code/ItDelight/FunctionalTest/Test/Mftf/Test/StorefrontExampleTest.xml
[...]
<actionGroup ref="CustomerLoginExampleActionGroup" stepKey="loginToStorefront">
<argument name="Customer" value="$$createCustomer$$"/>
</actionGroup>
<actionGroup ref="CheckClearShoppingCartActionGroup" stepKey="checkClearShoppingCartButton">
<argument name="Product" value="$$createSimpleProduct$$"/>
</actionGroup>
</test>
</tests>
Add a redirect to the product view page in the new action group. We use the existing product page in Magento for redirects with parameter var1 in the tag <url>.
Parameterization allows using different product URLs to build redirects.
vendor/magento/module-downloadable/Test/Mftf/Page/StorefrontProductPage.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright (c) 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="StorefrontProductPage" url="/{{var1}}.html" area="storefront" module="Magento_Catalog" parameterized="true">
<section name="StorefrontDownloadableProductSection" />
</page>
</pages>
app/code/ItDelight/FunctionalTest/Test/Mftf/ActionGroup/CheckClearShoppingCartActionGroup.xml
<?xml version="1.0" encoding="UTF-8"?>
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
<actionGroup name="CheckClearShoppingCartActionGroup">
<annotations>
<description>Goes to product view page and check Clear Shopping Cart button in the cart.</description>
</annotations>
<arguments>
<argument name="Product"/>
</arguments>
<amOnPage url="{{StorefrontProductPage.url(Product.custom_attributes[url_key])}}" stepKey="goToSimpleProductViewPage"/>
<waitForPageLoad stepKey="waitProductPage"/>
</actionGroup>
</actionGroups>
Add the product to the cart and check the success message to ensure that it was successfully added. Create an XML section with selectors needed for the product detail page.
app/code/ItDelight/FunctionalTest/Test/Mftf/Section/StorefrontProductDetailPageSection.xml
<?xml version="1.0" encoding="UTF-8"?>
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
<section name="StorefrontProductDetailPageSection">
<element name="pageTitle" type="text" selector=".page-title > span"/>
<element name="addToCartButton" type="button" selector="button.action.tocart.primary"/>
<element name="successMessage" type="text" selector="div.message-success"/>
</section>
</sections>
app/code/ItDelight/FunctionalTest/Test/Mftf/ActionGroup/CheckClearShoppingCartActionGroup.xml
[...]
<waitForPageLoad stepKey="waitProductPage"/>
<see stepKey="seeTitle" userInput="{{Product.name}}" selector="{{StorefrontProductDetailPageSection.pageTitle}}" />
<click stepKey="addToCart" selector="{{StorefrontProductDetailPageSection.addToCartButton}}"/>
<waitForAjaxLoad stepKey="waitAddProduct"/>
<see stepKey="successMessage" selector="{{StorefrontProductDetailPageSection.successMessage}}" userInput="You added {{Product.name}} to your shopping cart."/>
</actionGroup>
</actionGroups>
Now we go to the cart page and check the “Clear Shopping Cart” button, enabled earlier in the configuration. We will use XML instructions for functional tests existing in Magento. The checkout page section has all the needed selectors vendor/magento/module-checkout/Test/Mftf/Section/CheckoutCartProductSection.xml, the checkout cart page for redirecting to checkout cart page vendor/magento/module-checkout/Test/Mftf/Page/CheckoutCartPage.xml, and vendor/magento/module-checkout/Test/Mftf/Section/CheckoutCartMessageSection.xml for the validating message after removing the product from the cart.
app/code/ItDelight/FunctionalTest/Test/Mftf/ActionGroup/CheckClearShoppingCartActionGroup.xml
[...]
<see stepKey="successMessage" selector="{{StorefrontProductDetailPageSection.successMessage}}" userInput="You added {{Product.name}} to your shopping cart."/>
<amOnPage url="{{CheckoutCartPage.url}}" stepKey="openCartPage" />
<waitForPageLoad stepKey="waitForPageLoaded" />
<waitForElementVisible selector="{{CheckoutCartProductSection.emptyCartButton}}" stepKey="waitForEmptyCartButton"/>
<click selector="{{CheckoutCartProductSection.emptyCartButton}}" stepKey="clickEmptyCartButton"/>
<waitForElementVisible selector="{{CheckoutCartProductSection.modalMessage}}" stepKey="waitForModalMessage"/>
<waitForText selector="{{CheckoutCartProductSection.modalMessage}}" userInput="Are you sure you want to remove all items from your shopping cart?" stepKey="waitForTextModalMessage"/>
<waitForElementVisible selector="{{CheckoutCartProductSection.modalConfirmButton}}" stepKey="waitForModalConfirmButton"/>
<click selector="{{CheckoutCartProductSection.modalConfirmButton}}" stepKey="clickModalConfirmButton"/>
<waitForPageLoad stepKey="waitForPageLoad"/>
<seeCurrentUrlEquals url="{{_ENV.MAGENTO_BASE_URL}}checkout/cart" stepKey="seeCurrentUrlEqualsCartPage"/>
<waitForText selector="{{CheckoutCartMessageSection.emptyCartMessage}}" userInput="You have no items in your shopping cart." stepKey="waitForEmptyCartMessage"/>
</actionGroup>
</actionGroups>
{{_ENV.MAGENTO_BASE_URL}} – this is an environment variable from the dev/tests/acceptance/.env. We can define any variables that will be changed during the test. It will save time on making new changes to the version control system of our project.
Sum up
Today, we wrote the functional test. It creates the customer and product entities, changes configuration, runs CLI commands, login as a customer, and adds and removes the product from the cart. We also learned how to work with the main XML instructions and base structure for building test instructions.