diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..601e7f62d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Declare files that will always have LF line endings on checkout. +dev/tests/verification/Resources/TestSuiteGeneration1.txt text=auto !eol +dev/tests/verification/Resources/*.txt text eol=lf \ No newline at end of file diff --git a/LICENSE_APL3 b/LICENSE_AGPL3.txt similarity index 100% rename from LICENSE_APL3 rename to LICENSE_AGPL3.txt diff --git a/README.md b/README.md index f93325c42..906a4b01f 100755 --- a/README.md +++ b/README.md @@ -1,17 +1,70 @@ -# Magento2 Functional Testing Framework +# Magento Functional Testing Framework -Customized codeception modules, helpers, page objects and step objects for Magento 2.2.x. This library package can be used as dependency for Magento Acceptance Test projects for Magento 2 Community Edition ([magento/acceptance-test-ce](https://github.com/magento-pangolin/acceptance-test-ce/)) or Magento 2 Enterprise Edition in ([magento/acceptance-test-ee](https://github.com/magento-pangolin/acceptance-test-ee/)) or acceptance test projects for Magento 2 extensions. +---- + +## System Requirements +[Magento Functional Testing Framework system requirements](http://devdocs.magento.com/guides/v2.3/magento-functional-testing-framework/getting-started.html#prepare-environment) ## Installation -Add the package into your acceptance test project composer.json: -``` - { - "require": { - "magento/acceptance-test-framework": "dev-develop" - } - } -``` -Then run: -``` - composer update -``` +To install the Magento Functional Testing Framework, see [Getting Started](http://devdocs.magento.com/guides/v2.3/magento-functional-testing-framework/getting-started.html) + +## Contributing +Contributions can take the form of new components or features, changes to existing features, tests, documentation (such as developer guides, user guides, examples, or specifications), bug fixes, optimizations, or just good suggestions. + +To learn about how to make a contribution, click [here][1]. + +To open an issue, click [here][2]. + +To suggest documentation improvements, click [here][3]. + +[1]: +[2]: +[3]: + +### Labels applied by the MFTF team + +Refer to the tables with descriptions of each label below. These labels are applied by the MFTF development team to community contributed issues and pull requests, to communicate status, impact, or which team is working on it. + +### Pull Request Status + +Label| Description +---|--- +**accept**| The pull request has been accepted and will be merged into mainline code. +**reject**| The pull request has been rejected and will not be merged into mainline code. Possible reasons can include but are not limited to: issue has already been fixed in another code contribution, or there is an issue with the code contribution. +**needsUpdate**| The Magento Team needs additional information from the reporter to properly prioritize and process the pull request. + +### Issue Resolution Status + +Label| Description +---|--- +**acknowledged**| The Magento Team has validated the issue and an internal ticket has been created. +**needsUpdate**| The Magento Team needs additional information from the reporter to properly prioritize and process the issue or pull request. +**cannot reproduce**| The Magento Team has not confirmed that this issue contains the minimum required information to reproduce. +**non-issue**| The Magento Team has not recognised any issue according to provided information. + +### Domains Impacted + +Label| Description +---|--- +**PROD**| Affects the Product team (mostly feature requests or business logic change). +**DOC**| Affects Documentation domain. +**TECH**| Affects Architect Group (mostly to make decisions around technology changes). + +### Type + +Label| Description +---|--- +**bugfix**| The issue or pull request relates to bug fixing. +**enhancement**| The issue or pull request that raises the MFTF to a higher degree (for example new features, optimization, refactoring, etc). + +## Reporting security issues + +To report security vulnerabilities in Magento software or web sites, please e-mail security@magento.com. Please do not report security issues using GitHub. Be sure to encrypt your e-mail with our encryption key if it includes sensitive information. Learn more about reporting security issues here. + +Stay up-to-date on the latest security news and patches for Magento by signing up for Security Alert Notifications. + +## License + +Each Magento source file included in this distribution is licensed under AGPL 3.0 + +Please see LICENSE_AGPL3.txt for the full text of the AGPL 3.0 license or contact license@magentocommerce.com for a copy. diff --git a/bin/blacklist.txt b/bin/blacklist.txt index c85d25b5c..ea81ed858 100644 --- a/bin/blacklist.txt +++ b/bin/blacklist.txt @@ -6,4 +6,5 @@ bin/blacklist.txt dev/tests/static/Magento/Sniffs/Annotations/Helper.php dev/tests/static/Magento/Sniffs/Annotations/RequireAnnotatedAttributesSniff.php -dev/tests/static/Magento/Sniffs/Annotations/RequireAnnotatedMethodsSniff.php \ No newline at end of file +dev/tests/static/Magento/Sniffs/Annotations/RequireAnnotatedMethodsSniff.php +dev/tests/verification/_generated diff --git a/bin/phpunit-checks b/bin/phpunit-checks index 1fbbb4b19..7c4fd642e 100755 --- a/bin/phpunit-checks +++ b/bin/phpunit-checks @@ -1,8 +1,14 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. -echo "===============================UNIT TESTS===============================" -vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite unit --coverage-xml build/coverage-xml +set -e -echo "===============================VERIFICATION TESTS===============================" -vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite verification --coverage-xml build/coverage-xml +echo "===============================" +echo " UNIT TESTS" +echo "===============================" +vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite unit + +echo "===============================" +echo " VERIFICATION TESTS" +echo "===============================" +vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite verification diff --git a/bin/phpunit-checks.bat b/bin/phpunit-checks.bat new file mode 100644 index 000000000..de5cebdef --- /dev/null +++ b/bin/phpunit-checks.bat @@ -0,0 +1,10 @@ +:: Copyright © Magento, Inc. All rights reserved. +:: See COPYING.txt for license details. + +@echo ===============================UNIT TESTS=============================== +@echo off +call vendor\bin\phpunit --configuration dev\tests\phpunit.xml --testsuite unit --coverage-xml build\coverage-xml + +@echo off +@echo ===============================VERIFICATION TESTS=============================== +call vendor\bin\phpunit --configuration dev\tests\phpunit.xml --testsuite verification --coverage-xml build\coverage-xml \ No newline at end of file diff --git a/bin/static-checks b/bin/static-checks index cdc6b8c7b..c6526e3be 100755 --- a/bin/static-checks +++ b/bin/static-checks @@ -1,13 +1,31 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. -echo "===============================PHP CODE SNIFFER REPORT===============================" +set -e + +echo "===============================" +echo " CODE SNIFFER" +echo "===============================" vendor/bin/phpcs ./src --standard=./dev/tests/static/Magento vendor/bin/phpcs ./dev/tests/unit --standard=./dev/tests/static/Magento -vendor/bin/phpcs ./dev/tests/verification --standard=./dev/tests/static/Magento +vendor/bin/phpcs ./dev/tests/verification --standard=./dev/tests/static/Magento --ignore=dev/tests/verification/_generated +echo "" -echo "===============================COPY PASTE DETECTOR REPORT===============================" +echo "===============================" +echo " COPY PASTE DETECTOR" +echo "===============================" vendor/bin/phpcpd ./src +echo "" + +# Uncomment lines as part of MQE-590 +# echo "===============================" +# echo " MESS DETECTOR" +# echo "===============================" +# vendor/bin/phpmd ./src text /dev/tests/static/Magento/CodeMessDetector/ruleset.xml --exclude _generated +# echo "" -echo "===============================MAGENTO COPYRIGHT REPORT===============================" +echo "===============================" +echo " MAGENTO COPYRIGHT CHECK" +echo "===============================" bin/copyright-check +echo "" diff --git a/bin/static-checks.bat b/bin/static-checks.bat new file mode 100644 index 000000000..7614c7846 --- /dev/null +++ b/bin/static-checks.bat @@ -0,0 +1,20 @@ +:: Copyright © Magento, Inc. All rights reserved. +:: See COPYING.txt for license details. + +@echo off +@echo ===============================PHP CODE SNIFFER REPORT=============================== +call vendor\bin\phpcs .\src --standard=.\dev\tests\static\Magento +call vendor\bin\phpcs .\dev\tests\unit --standard=.\dev\tests\static\Magento +call vendor\bin\phpcs .\dev\tests\verification --standard=.\dev\tests\static\Magento --ignore=dev\tests\verification\_generated + +@echo ===============================COPY PASTE DETECTOR REPORT=============================== +call vendor\bin\phpcpd .\src + +:: Uncomment lines as part of MQE-590 +:: @echo "===============================PHP MESS DETECTOR REPORT=============================== +:: vendor\bin\phpmd .\src text \dev\tests\static\Magento\CodeMessDetector\ruleset.xml --exclude _generated + +@echo ===============================MAGENTO COPYRIGHT REPORT=============================== +echo msgbox "INFO:Copyright check currently not run as part of .bat implementation" > "%temp%\popup.vbs" +wscript.exe "%temp%\popup.vbs" +::bin\copyright-check \ No newline at end of file diff --git a/changelog.md b/changelog.md new file mode 100644 index 000000000..579b23850 --- /dev/null +++ b/changelog.md @@ -0,0 +1,20 @@ +MFTF Version 1.0 - Changelog + +Core Features: + +Supported Systems: +OS + Windows 10 + OSX (Sierra) + +Browser + Chrome (Latest) with ChromeDriver Latest + + +Known Issues: +*Support for Firefox is curently incomplete. This will be resolved to support Firefox 57 (Quantum) and latest Gecko driver in next minor release. + + + + + diff --git a/composer.json b/composer.json index b98c2ef22..8f6a8dd86 100755 --- a/composer.json +++ b/composer.json @@ -1,31 +1,37 @@ { "name": "magento/magento2-functional-testing-framework", - "type": "library", "description": "Magento2 Functional Testing Framework", + "type": "library", + "version": "1.0.0", + "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], + "config": { + "sort-packages": true + }, "require": { "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", "codeception/codeception": "~2.3.4", + "epfremme/swagger-php": "^2.0", "flow/jsonpath": ">0.2", "fzaninotto/faker": "^1.6", - "mustache/mustache": "~2.5", - "epfremme/swagger-php": "^2.0" + "mustache/mustache": "~2.5" }, "require-dev": { "squizlabs/php_codesniffer": "1.5.3", "sebastian/phpcpd": "~3.0", "brainmaestro/composer-git-hooks": "^2.3", "codeception/aspect-mock": "^2.0", - "codacy/coverage": "^1.4" + "codacy/coverage": "^1.4", + "phpmd/phpmd": "^2.6.0" }, "autoload": { "psr-4": { - "Magento\\FunctionalTestingFramework\\": ["src/Magento/FunctionalTestingFramework"] + "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework" } }, "autoload-dev": { "psr-4": { - "tests\\unit\\Magento\\FunctionalTestingFramework\\": ["dev/tests/unit/Magento/FunctionalTestingFramework"] + "tests\\unit\\Magento\\FunctionalTestingFramework\\": "dev/tests/unit/Magento/FunctionalTestingFramework" } }, "extra": { diff --git a/dev/tests/static/Magento/CodeMessDetector/Rule/Design/FinalImplementation.php b/dev/tests/static/Magento/CodeMessDetector/Rule/Design/FinalImplementation.php new file mode 100644 index 000000000..22c008b05 --- /dev/null +++ b/dev/tests/static/Magento/CodeMessDetector/Rule/Design/FinalImplementation.php @@ -0,0 +1,29 @@ +isFinal()) { + $this->addViolation($node, [$node->getType(), $node->getFullQualifiedName()]); + } + } +} diff --git a/dev/tests/static/Magento/CodeMessDetector/resources/rulesets/design.xml b/dev/tests/static/Magento/CodeMessDetector/resources/rulesets/design.xml new file mode 100644 index 000000000..61d4f7b3b --- /dev/null +++ b/dev/tests/static/Magento/CodeMessDetector/resources/rulesets/design.xml @@ -0,0 +1,36 @@ + + + + + + + + 1 + + + + + + diff --git a/dev/tests/static/Magento/CodeMessDetector/ruleset.xml b/dev/tests/static/Magento/CodeMessDetector/ruleset.xml new file mode 100644 index 000000000..34fce51d0 --- /dev/null +++ b/dev/tests/static/Magento/CodeMessDetector/ruleset.xml @@ -0,0 +1,50 @@ + + + + Magento Code Check Rules + ../../../static + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index 513c80e9b..4b57a2f73 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -20,14 +20,14 @@ class OperationDataArrayResolverTest extends TestCase "name" => "Hopper", "address" => ["city" => "Hawkins", "state" => "Indiana", "zip" => 78758], "isPrimary" => true, - "gpa" => 3.5, + "gpa" => 3.5678, "phone" => 5555555 ]]; const NESTED_METADATA_ARRAY_RESULT = ["parentType" => [ "name" => "Hopper", "isPrimary" => true, - "gpa" => 3.5, + "gpa" => 3.5678, "phone" => 5555555, "address" => [ ["city" => "Hawkins", "state" => "Indiana", "zip" => 78758], @@ -65,7 +65,7 @@ public function testBasicPrimitiveMetadataResolve() // assert on result $expectedResult = ["testType" => [ "name" => "Hopper", - "gpa" => 3.5, + "gpa" => 3.5678, "phone" => 5555555, "isPrimary" => true ]]; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 5ab71810c..17e6ad468 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -27,7 +27,7 @@ class ActionObjectTest extends TestCase */ public function testConstructOrderBefore() { - $actionObject = new ActionObject('mergeKey', 'type', [], null, 'before'); + $actionObject = new ActionObject('stepKey', 'type', [], null, 'before'); $this->assertEquals(0, $actionObject->getOrderOffset()); } @@ -36,7 +36,7 @@ public function testConstructOrderBefore() */ public function testConstructOrderAfter() { - $actionObject = new ActionObject('mergeKey', 'type', [], null, 'after'); + $actionObject = new ActionObject('stepKey', 'type', [], null, 'after'); $this->assertEquals(1, $actionObject->getOrderOffset()); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index bbe88bf54..bae9965dd 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -16,23 +16,6 @@ class ActionMergeUtilTest extends TestCase { - /** - * Static ActionMergeUtil for all tests. - * - * @var ActionMergeUtil - */ - private static $MERGE_UTIL; - - /** - * Set up method for ActionMergeUtil tests. - * - * @return void - */ - public static function setUpBeforeClass() - { - self::$MERGE_UTIL = new ActionMergeUtil("actionMergeUtilTest", "TestCase"); - } - /** * Test to validate actions are properly ordered during a merge. * @@ -49,43 +32,44 @@ public function testResolveActionStepOrdering() $testObjNamePosAfterEnd = 'testAfterAfterMerge10'; for ($i = 1; $i < $actionsLength; $i++) { - $mergeKey = 'mergeKey'. $i; + $stepKey = 'stepKey'. $i; $type = 'testType'; $actionAttributes = []; - $actions[] = new ActionObject($mergeKey, $type, $actionAttributes); + $actions[] = new ActionObject($stepKey, $type, $actionAttributes); } $actions[] = new ActionObject( $testObjNamePosAfterEnd, - 'mergeType', + 'stepType', [], $testObjNamePosEnd, ActionObject::MERGE_ACTION_ORDER_AFTER ); $actions[] = new ActionObject( $testObjNamePosBeforeFirst, - 'mergeType', + 'stepType', [], $testObjNamePosFirst, ActionObjectExtractor::TEST_ACTION_BEFORE ); $actions[] = new ActionObject( $testObjNamePosFirst, - 'mergeType', + 'stepType', [], - 'mergeKey1', + 'stepKey1', ActionObjectExtractor::TEST_ACTION_BEFORE ); $actions[] = new ActionObject( $testObjNamePosEnd, - 'mergeType', + 'stepType', [], - 'mergeKey' . (string)($actionsLength - 1), + 'stepKey' . (string)($actionsLength - 1), ActionObject::MERGE_ACTION_ORDER_AFTER ); - $orderedActions = self::$MERGE_UTIL->resolveActionSteps($actions); + $mergeUtil = new ActionMergeUtil("actionMergeUtilTest", "TestCase"); + $orderedActions = $mergeUtil->resolveActionSteps($actions); $orderedActionKeys = array_keys($orderedActions); $this->assertEquals($testObjNamePosBeforeFirst, $orderedActionKeys[0]); @@ -94,26 +78,6 @@ public function testResolveActionStepOrdering() $this->assertEquals($testObjNamePosAfterEnd, $orderedActionKeys[$actionsLength + 2]); } - /** - * Test to validate action steps properly resolve section element references. - * - * @return void - */ - public function testResolveActionStepSectionData() - { - $this->markTestIncomplete('TODO'); - } - - /** - * Test to validate action steps properly resolve page references. - * - * @return void - */ - public function testResolveActionStepPageData() - { - $this->markTestIncomplete('TODO'); - } - /** * Test to validate action steps properly resolve entity data references. * @@ -149,4 +113,54 @@ public function testResolveActionStepEntityData() $this->assertEquals($dataFieldValue, $resolvedActions[$actionName]->getCustomActionAttributes()[$userInputKey]); } + + /** + * Verify that an XmlException is thrown when an action references a non-existant action. + * + * @return void + */ + public function testNoActionException() + { + $actionObjects = []; + + $actionObjects[] = new ActionObject('actionKey1', 'bogusType', []); + $actionObjects[] = new ActionObject( + 'actionKey2', + 'bogusType', + [], + 'badActionReference', + ActionObject::MERGE_ACTION_ORDER_BEFORE + ); + + $this->expectException("\Magento\FunctionalTestingFramework\Exceptions\XmlException"); + + $actionMergeUtil = new ActionMergeUtil("actionMergeUtilTest", "TestCase"); + $actionMergeUtil->resolveActionSteps($actionObjects); + } + + /** + * Verify that a action is added after actions that have a wait (timeout property). + * + * @return void + */ + public function testInsertWait() + { + $actionObjectOne = new ActionObject('actionKey1', 'bogusType', []); + $actionObjectOne->setTimeout(42); + $actionObjects = [$actionObjectOne]; + + $actionMergeUtil = new ActionMergeUtil("actionMergeUtilTest", "TestCase"); + $result = $actionMergeUtil->resolveActionSteps($actionObjects); + + $actual = $result['actionKey1WaitForPageLoad']; + $expected = new ActionObject( + 'actionKey1WaitForPageLoad', + 'waitForPageLoad', + ['timeout' => 42], + 'actionKey1', + 0 + ); + $this->assertEquals($expected, $actual); + + } } diff --git a/dev/tests/unit/Util/EntityDataObjectBuilder.php b/dev/tests/unit/Util/EntityDataObjectBuilder.php index ead183b8c..dfe7d6836 100644 --- a/dev/tests/unit/Util/EntityDataObjectBuilder.php +++ b/dev/tests/unit/Util/EntityDataObjectBuilder.php @@ -16,7 +16,7 @@ class EntityDataObjectBuilder */ private $data = [ "name" => "Hopper", - "gpa" => "3.5", + "gpa" => "3.5678", "phone" => "5555555", "isprimary" => "true" ]; diff --git a/dev/tests/unit/Util/OperationElementBuilder.php b/dev/tests/unit/Util/OperationElementBuilder.php index a7a021ac2..cf9322e17 100644 --- a/dev/tests/unit/Util/OperationElementBuilder.php +++ b/dev/tests/unit/Util/OperationElementBuilder.php @@ -18,7 +18,7 @@ class OperationElementBuilder */ private $fields = [ 'name' => 'string', - 'gpa' => 'double', + 'gpa' => 'number', 'phone' => 'integer', 'isPrimary' => 'boolean' ]; diff --git a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt index 9a14b0702..00697e8f2 100644 --- a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt +++ b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt @@ -31,7 +31,7 @@ class ActionGroupFunctionalCest public function _before(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: createPersonParam"); + $I->amGoingTo("create entity that has the stepKey: createPersonParam"); $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); $this->createPersonParam = new DataPersistenceHandler($ReplacementPerson); $this->createPersonParam->createEntity(); @@ -111,7 +111,7 @@ class ActionGroupFunctionalCest */ public function ActionGroupWithPersistedData(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: createPerson"); + $I->amGoingTo("create entity that has the stepKey: createPerson"); $DefaultPerson = DataObjectHandler::getInstance()->getObject("DefaultPerson"); $createPerson = new DataPersistenceHandler($DefaultPerson); $createPerson->createEntity(); @@ -170,4 +170,15 @@ class ActionGroupFunctionalCest $I->amOnPage("/Jane/Dane.html"); } + /** + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + */ + public function ArgumentWithSameNameAsElement(AcceptanceTester $I) + { + $I->seeElement("#element"); + $I->seeElement("#element .John"); + } + } diff --git a/dev/tests/verification/Resources/AssertCest.txt b/dev/tests/verification/Resources/AssertCest.txt index fd2fe2259..1affb20db 100644 --- a/dev/tests/verification/Resources/AssertCest.txt +++ b/dev/tests/verification/Resources/AssertCest.txt @@ -26,7 +26,7 @@ class AssertCest public function _before(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: createData1"); + $I->amGoingTo("create entity that has the stepKey: createData1"); $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); $this->createData1 = new DataPersistenceHandler($ReplacementPerson); $this->createData1->createEntity(); @@ -39,7 +39,7 @@ class AssertCest */ public function AssertTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: createData2"); + $I->amGoingTo("create entity that has the stepKey: createData2"); $UniquePerson = DataObjectHandler::getInstance()->getObject("UniquePerson"); $createData2 = new DataPersistenceHandler($UniquePerson); $createData2->createEntity(); @@ -98,5 +98,13 @@ class AssertCest $I->fail("fail"); $I->fail($createData2->getCreatedDataByName('firstname') . " " . $createData2->getCreatedDataByName('lastname')); $I->fail($this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); + $I->assertElementContainsAttribute("#username", "class", "admin__control-text"); + $I->assertElementContainsAttribute("#username", "name", "login[username]"); + $I->assertElementContainsAttribute("#username", "autofocus", ""); + $I->assertElementContainsAttribute("#username", "data-validate", "{required:true}"); + $I->assertElementContainsAttribute(".admin__menu-overlay", "style", "display: none;"); + $I->assertElementContainsAttribute(".admin__menu-overlay", "border", "0"); + $I->assertElementContainsAttribute("#username", "value", $createData2->getCreatedDataByName('firstname')); + $I->assertElementContainsAttribute("#username", "value", $this->createData1->getCreatedDataByName('firstname')); } } diff --git a/dev/tests/verification/Resources/BasicFunctionalCest.txt b/dev/tests/verification/Resources/BasicFunctionalCest.txt index b7afc27d9..fdb7b83cc 100644 --- a/dev/tests/verification/Resources/BasicFunctionalCest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalCest.txt @@ -57,7 +57,7 @@ class BasicFunctionalCest $I->clickWithLeftButton(".functionalTestSelector"); $I->clickWithRightButton(".functionalTestSelector"); $I->closeTab(); - $I->conditionalClick(".functionalTestSelector", ".functionalDependentTestSelector"); + $I->conditionalClick(".functionalTestSelector", ".functionalDependentTestSelector", true); $I->dontSee("someInput", ".functionalTestSelector"); $I->dontSeeCheckboxIsChecked(".functionalTestSelector"); $I->dontSeeCookie("someInput"); diff --git a/dev/tests/verification/Resources/LocatorFunctionCest.txt b/dev/tests/verification/Resources/LocatorFunctionCest.txt index b716443c0..17b1136b6 100644 --- a/dev/tests/verification/Resources/LocatorFunctionCest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionCest.txt @@ -26,7 +26,7 @@ class LocatorFunctionCest */ public function LocatorFuctionTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: data"); + $I->amGoingTo("create entity that has the stepKey: data"); $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); $data = new DataPersistenceHandler($ReplacementPerson); $data->createEntity(); diff --git a/dev/tests/verification/Resources/MergeFunctionalCest.txt b/dev/tests/verification/Resources/MergeFunctionalCest.txt index 36fc00b80..78a8456f3 100644 --- a/dev/tests/verification/Resources/MergeFunctionalCest.txt +++ b/dev/tests/verification/Resources/MergeFunctionalCest.txt @@ -54,6 +54,7 @@ class MergeFunctionalCest $I->fillField("#bar", "Dane"); $I->searchAndMultiSelectOption("#foo", ["Jane", "Dane"]); $I->see("#element .Jane"); + $I->click("#step10MergedInResult"); } /** diff --git a/dev/tests/verification/Resources/PageReplacementCest.txt b/dev/tests/verification/Resources/PageReplacementCest.txt index bfb459b5b..788513e31 100644 --- a/dev/tests/verification/Resources/PageReplacementCest.txt +++ b/dev/tests/verification/Resources/PageReplacementCest.txt @@ -26,7 +26,7 @@ class PageReplacementCest */ public function PageReplacementTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: datakey"); + $I->amGoingTo("create entity that has the stepKey: datakey"); $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); $datakey = new DataPersistenceHandler($simpleData); $datakey->createEntity(); diff --git a/dev/tests/verification/Resources/ParameterArrayCest.txt b/dev/tests/verification/Resources/ParameterArrayCest.txt index c07354af1..29950491a 100644 --- a/dev/tests/verification/Resources/ParameterArrayCest.txt +++ b/dev/tests/verification/Resources/ParameterArrayCest.txt @@ -26,7 +26,7 @@ class ParameterArrayCest */ public function ParameterArrayTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: simpleDataKey"); + $I->amGoingTo("create entity that has the stepKey: simpleDataKey"); $simpleParamData = DataObjectHandler::getInstance()->getObject("simpleParamData"); $simpleDataKey = new DataPersistenceHandler($simpleParamData); $simpleDataKey->createEntity(); diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index 4ff8d853e..1e2d8d325 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -26,7 +26,7 @@ class PersistedReplacementCest public function _before(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: createData1"); + $I->amGoingTo("create entity that has the stepKey: createData1"); $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); $this->createData1 = new DataPersistenceHandler($ReplacementPerson); $this->createData1->createEntity(); @@ -39,7 +39,7 @@ class PersistedReplacementCest */ public function PersistedReplacementTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: createdData"); + $I->amGoingTo("create entity that has the stepKey: createdData"); $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); $createdData = new DataPersistenceHandler($simpleData); $createdData->createEntity(); diff --git a/dev/tests/verification/Resources/SectionReplacementCest.txt b/dev/tests/verification/Resources/SectionReplacementCest.txt index 333f5ac4f..2fb4d0b29 100644 --- a/dev/tests/verification/Resources/SectionReplacementCest.txt +++ b/dev/tests/verification/Resources/SectionReplacementCest.txt @@ -45,7 +45,7 @@ class SectionReplacementCest $I->click("#Doe".msq("uniqueData")." .stringLiteral2"); $I->click("#Doe".msq("uniqueData")."-stringLiteral2 .stringLiteral3"); $I->click("#Doe".msq("uniqueData")."-stringLiteral2 .Doe"); - $I->amGoingTo("create entity that has the mergeKey: createdData"); + $I->amGoingTo("create entity that has the stepKey: createdData"); $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); $createdData = new DataPersistenceHandler($simpleData); $createdData->createEntity(); diff --git a/dev/tests/verification/Resources/TestSuiteGeneration1.txt b/dev/tests/verification/Resources/TestSuiteGeneration1.txt deleted file mode 100644 index 620dacd7e..000000000 --- a/dev/tests/verification/Resources/TestSuiteGeneration1.txt +++ /dev/null @@ -1,4 +0,0 @@ -dev/tests/verification/_generated/functionalSuite1/SampleSuite3Cest.php:IncludeTest -dev/tests/verification/_generated/functionalSuite1/SampleSuite5Cest.php:additionalTest -dev/tests/verification/_generated/functionalSuite1/SampleSuiteCest.php:IncludeTest -dev/tests/verification/_generated/functionalSuite1/SampleSuite4Cest.php:IncludeTest diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml index a4b1e4cd6..8215dbe97 100644 --- a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml @@ -9,33 +9,40 @@ - - + + - - - - - + + + + + - - - + + + - - - + + + + + + + + + + diff --git a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml index 37f648f43..eb62a5cd8 100644 --- a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml @@ -9,8 +9,8 @@ - - - + + + diff --git a/dev/tests/verification/TestModule/Cest/ActionGroupFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/ActionGroupFunctionalCest.xml index ed3c5cdce..e9c677c64 100644 --- a/dev/tests/verification/TestModule/Cest/ActionGroupFunctionalCest.xml +++ b/dev/tests/verification/TestModule/Cest/ActionGroupFunctionalCest.xml @@ -17,59 +17,62 @@ - - + + - - - + + + - - - + + + - - + + - + - - + + - + - - + + - + - - - - + + + + - + + + + - + diff --git a/dev/tests/verification/TestModule/Cest/AssertCest.xml b/dev/tests/verification/TestModule/Cest/AssertCest.xml index 9444da9f6..f50bd3299 100644 --- a/dev/tests/verification/TestModule/Cest/AssertCest.xml +++ b/dev/tests/verification/TestModule/Cest/AssertCest.xml @@ -10,72 +10,82 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml index 28578bd44..9d0d89035 100644 --- a/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml +++ b/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml @@ -17,10 +17,10 @@ - + - + @@ -30,89 +30,89 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/DataReplacementCest.xml b/dev/tests/verification/TestModule/Cest/DataReplacementCest.xml index 1e33dd731..e466e6684 100644 --- a/dev/tests/verification/TestModule/Cest/DataReplacementCest.xml +++ b/dev/tests/verification/TestModule/Cest/DataReplacementCest.xml @@ -10,27 +10,27 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml b/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml index 497320d15..3865bb0ac 100644 --- a/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml +++ b/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml @@ -10,23 +10,23 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - + - - - + + + - - - + + + - - - + + + - - - + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/MergeBaseFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/MergeBaseFunctionalCest.xml index 01801c15b..592d8541f 100644 --- a/dev/tests/verification/TestModule/Cest/MergeBaseFunctionalCest.xml +++ b/dev/tests/verification/TestModule/Cest/MergeBaseFunctionalCest.xml @@ -17,20 +17,21 @@ - + - + - - - - + + + + + - - + + diff --git a/dev/tests/verification/TestModule/Cest/MergeInFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/MergeInFunctionalCest.xml index 304000252..bfc9ddb94 100644 --- a/dev/tests/verification/TestModule/Cest/MergeInFunctionalCest.xml +++ b/dev/tests/verification/TestModule/Cest/MergeInFunctionalCest.xml @@ -13,18 +13,19 @@ - + - + - - - - - - + + + + + + + diff --git a/dev/tests/verification/TestModule/Cest/PageReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PageReplacementCest.xml index 26ad49337..2bdbcb8c1 100644 --- a/dev/tests/verification/TestModule/Cest/PageReplacementCest.xml +++ b/dev/tests/verification/TestModule/Cest/PageReplacementCest.xml @@ -10,15 +10,15 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/ParameterArrayCest.xml b/dev/tests/verification/TestModule/Cest/ParameterArrayCest.xml index 8bd88fdd7..7dfe55943 100644 --- a/dev/tests/verification/TestModule/Cest/ParameterArrayCest.xml +++ b/dev/tests/verification/TestModule/Cest/ParameterArrayCest.xml @@ -7,19 +7,19 @@ --> + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - - - - - - - - - - + + + + + + + + + + diff --git a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml index 663c51ef7..02df18016 100644 --- a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml +++ b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml @@ -10,19 +10,19 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - + - + - - - - - - - - + + + + + + + + diff --git a/dev/tests/verification/TestModule/Cest/SampleSuiteCest.xml b/dev/tests/verification/TestModule/Cest/SampleSuiteCest.xml index 712fe2636..a88c91cab 100644 --- a/dev/tests/verification/TestModule/Cest/SampleSuiteCest.xml +++ b/dev/tests/verification/TestModule/Cest/SampleSuiteCest.xml @@ -10,16 +10,16 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - - - - + + + + - - - - + + + + @@ -27,10 +27,10 @@ - - - - + + + + @@ -38,16 +38,16 @@ - - - - + + + + - - - - + + + + @@ -55,16 +55,16 @@ - - - - + + + + - - - - + + + + @@ -72,16 +72,16 @@ - - - - + + + + - - - - + + + + diff --git a/dev/tests/verification/TestModule/Cest/SectionReplacementCest.xml b/dev/tests/verification/TestModule/Cest/SectionReplacementCest.xml index ca91fef27..4cd8c9e5b 100644 --- a/dev/tests/verification/TestModule/Cest/SectionReplacementCest.xml +++ b/dev/tests/verification/TestModule/Cest/SectionReplacementCest.xml @@ -10,39 +10,39 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Section/SampleSection.xml b/dev/tests/verification/TestModule/Section/SampleSection.xml index 63a525886..d4f3da09a 100644 --- a/dev/tests/verification/TestModule/Section/SampleSection.xml +++ b/dev/tests/verification/TestModule/Section/SampleSection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
+ diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 947069ad9..709d4da20 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -16,6 +16,13 @@ class SuiteGenerationTest extends TestCase const RESOURCES_DIR = TESTS_BP . DIRECTORY_SEPARATOR . 'verification' . DIRECTORY_SEPARATOR . 'Resources'; const CONFIG_YML_FILE = FW_BP . DIRECTORY_SEPARATOR . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME; + const MANIFEST_RESULTS = [ + 'SampleSuite3Cest.php:IncludeTest', + 'SampleSuite5Cest.php:additionalTest', + 'SampleSuiteCest.php:IncludeTest', + 'SampleSuite4Cest.php:IncludeTest' + ]; + private static $YML_EXISTS_FLAG = false; private static $TEST_GROUPS = []; @@ -45,18 +52,34 @@ public function testSuiteGeneration1() $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); $this->assertArrayHasKey($groupName, $yml['groups']); - // Validate test manifest contents - $actualManifest = TESTS_BP . + $suiteResultBaseDir = TESTS_BP . DIRECTORY_SEPARATOR . "verification" . DIRECTORY_SEPARATOR . "_generated" . DIRECTORY_SEPARATOR . $groupName . - DIRECTORY_SEPARATOR . - TestManifest::TEST_MANIFEST_FILENAME; - $expectedManifest = self::RESOURCES_DIR . DIRECTORY_SEPARATOR . "TestSuiteGeneration1.txt"; - $this->assertFileEquals($expectedManifest, $actualManifest, '', true, true); + DIRECTORY_SEPARATOR; + + // Validate test manifest contents + $actualManifest = $suiteResultBaseDir . TestManifest::TEST_MANIFEST_FILENAME; + $actualTestReferences = explode(PHP_EOL, file_get_contents($actualManifest)); + + for ($i = 0; $i < count($actualTestReferences); $i++) { + if (empty($actualTestReferences[$i])) { + continue; + } + + $this->assertStringEndsWith(self::MANIFEST_RESULTS[$i], $actualTestReferences[$i]); + $this->assertNotFalse(strpos($actualTestReferences[$i], $groupName)); + } + + // Validate expected php files exist + foreach (self::MANIFEST_RESULTS as $expectedTestReference) { + $cestName = explode(":", $expectedTestReference, 2); + $this->assertFileExists($suiteResultBaseDir . $cestName[0]); + } + } public static function tearDownAfterClass() diff --git a/etc/_envs/phantomjs.yml b/etc/_envs/phantomjs.yml deleted file mode 100644 index b26042a8c..000000000 --- a/etc/_envs/phantomjs.yml +++ /dev/null @@ -1,8 +0,0 @@ -# `phantomjs` environment config goes here -modules: - enabled: - - \Magento\FunctionalTestingFramework\Module\MagentoWebDriver - - \Magento\FunctionalTestingFramework\Helper\Acceptance - config: - \Magento\FunctionalTestingFramework\Module\MagentoWebDriver: - browser: 'phantomjs' \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index c6e77e5b8..61c89cf5b 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -208,7 +208,10 @@ createDataKey createDataKey createDataKey - mergeKey + stepKey + keyForRemoval + keyForRemoval + keyForRemoval *Cest.xml Cest @@ -218,9 +221,12 @@ - mergeKey - mergeKey - mergeKey + stepKey + stepKey + stepKey + keyForRemoval + keyForRemoval + keyForRemoval name name createDataKey @@ -286,7 +292,8 @@ name name - mergeKey + stepKey + keyForRemoval *ActionGroup.xml ActionGroup @@ -296,7 +303,8 @@ - mergeKey + stepKey + keyForRemoval name name @@ -360,8 +368,8 @@ name - mergeKey - mergeKey + stepKey + stepKey createDataKey createDataKey name diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Mask.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Mask.php index b708ee052..e3f29f954 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Mask.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Mask.php @@ -64,7 +64,7 @@ protected function getFileCollection($filename, $scope) $modulesPath = $this->moduleResolver->getModulesPath(); foreach ($modulesPath as $modulePath) { - $path = $modulePath . '/' . $scope . '/'; + $path = $modulePath . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR; if (is_readable($path)) { $directoryIterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php index 14643b32e..2376b3cf1 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php @@ -28,7 +28,7 @@ public function get($filename, $scope) if (!$filename) { return []; } - $scope = str_replace('\\', '/', $scope); + $scope = str_replace('\\', DIRECTORY_SEPARATOR, $scope); return new File($this->getFilePaths($filename, $scope)); } @@ -59,19 +59,20 @@ private function getPathPatterns($filename, $scope) { if (substr($scope, 0, strlen(FW_BP)) === FW_BP) { $patterns = [ - $scope . '/' . $filename, - $scope . '/*/' . $filename + $scope . DIRECTORY_SEPARATOR . $filename, + $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . $filename ]; } else { $defaultPath = dirname(dirname(dirname(dirname(__DIR__)))); - $defaultPath = str_replace('\\', '/', $defaultPath); + $defaultPath = str_replace('\\', DIRECTORY_SEPARATOR, $defaultPath); $patterns = [ - $defaultPath . '/' . $scope . '/' . $filename, - $defaultPath . '/' . $scope . '/*/' . $filename, - FW_BP . '/' . $scope . '/' . $filename, - FW_BP . '/' . $scope . '/*/' . $filename + $defaultPath . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . $filename, + $defaultPath . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR + . $filename, + FW_BP . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . $filename, + FW_BP . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . $filename ]; } - return str_replace('/', DIRECTORY_SEPARATOR, $patterns); + return str_replace(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, $patterns); } } diff --git a/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php b/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php index 628d7c674..1ff647161 100644 --- a/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php +++ b/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php @@ -25,12 +25,12 @@ class SchemaLocator implements \Magento\FunctionalTestingFramework\Config\Schema */ public function __construct($schemaPath) { - if (constant('FW_BP') && file_exists(FW_BP . '/' . $schemaPath)) { - $this->schemaPath = FW_BP . '/' . $schemaPath; + if (constant('FW_BP') && file_exists(FW_BP . DIRECTORY_SEPARATOR . $schemaPath)) { + $this->schemaPath = FW_BP . DIRECTORY_SEPARATOR . $schemaPath; } else { $path = dirname(dirname(dirname(__DIR__))); - $path = str_replace('\\', '/', $path); - $this->schemaPath = $path . '/' . $schemaPath; + $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); + $this->schemaPath = $path . DIRECTORY_SEPARATOR . $schemaPath; } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 0ca3d459a..f970d580e 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -116,7 +116,7 @@ private function initDataObjects() $entityParsedData = $entityParser->readDataProfiles(); if (!$entityParsedData) { - trigger_error("No entities could be parsed from xml definitions", E_USER_NOTICE); + // No *Data.xml files found so give up return; } @@ -132,7 +132,7 @@ private function initDataObjects() */ private function parseEnvVariables() { - $envFilename = PROJECT_ROOT . '/.env'; + $envFilename = PROJECT_ROOT . DIRECTORY_SEPARATOR . '.env'; if (file_exists($envFilename)) { $envData = []; $envFile = file($envFilename); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php index bbe713c06..7521acc10 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php @@ -18,7 +18,7 @@ class OperationDataArrayResolver 'string', 'boolean', 'integer', - 'double' + 'number' ]; const EXCEPTION_REQUIRED_DATA = "%s of key \" %s\" in \"%s\" is required by metadata, but was not provided."; @@ -362,8 +362,8 @@ private function castValue($type, $value) } $newVal = (boolean)$value; break; - case 'double': - $newVal = (double)$value; + case 'number': + $newVal = (float)$value; break; } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoRestDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoRestDriver.php index 790626629..cd8ae5143 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoRestDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoRestDriver.php @@ -104,6 +104,11 @@ class MagentoRestDriver extends REST public function _beforeSuite($settings = []) { parent::_beforeSuite($settings); + if (empty($this->config['url']) || empty($this->config['username']) || empty($this->config['password'])) { + return; + } + $this->config['url'] = $_ENV['MAGENTO_BASE_URL'] . "rest/default/V1/"; + $this->haveHttpHeader('Content-Type', 'application/json'); $this->sendPOST( 'integration/admin/token', diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoSequence.php b/src/Magento/FunctionalTestingFramework/Module/MagentoSequence.php index 6689e6b45..df59a62ec 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoSequence.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoSequence.php @@ -20,7 +20,7 @@ class MagentoSequence extends Sequence } if (!function_exists('msq') && !function_exists('msqs')) { - require_once __DIR__ . '/../Util/msq.php'; + require_once __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Util' . DIRECTORY_SEPARATOR . 'msq.php'; } else { throw new ModuleException('Magento\FunctionalTestingFramework\Module\MagentoSequence', "function 'msq' and 'msqs' already defined"); } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index b6e6e2800..7c7f52667 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -17,6 +17,7 @@ use Codeception\Exception\ModuleException; use Codeception\Util\Uri; use Codeception\Util\ActionSequence; +use Magento\Setup\Exception; use Yandex\Allure\Adapter\Support\AttachmentSupport; /** @@ -76,6 +77,96 @@ class MagentoWebDriver extends WebDriver LC_MESSAGES => null, ]; + public function _initialize() + { + $this->sanitizeConfig(); + parent::_initialize(); + } + + public function _resetConfig() + { + parent::_resetConfig(); + $this->sanitizeConfig(); + } + + /** + * Sanitizes URL and Selenium Variables, then assigns them to the config array. + * @return void + */ + private function sanitizeConfig() + { + if ($this->config['url'] === "") { + trigger_error("MAGENTO_BASE_URL must be defined in .env", E_USER_ERROR); + } + + //Determine if url sanitize is required + if (!preg_match("/(http|https):\/\/[\w.:]+\//", $this->config['url'])) { + $urlParts = parse_url($this->config['url']); + + if (!isset($urlParts['scheme'])) { + $urlParts['scheme'] = "http"; + } + if (!isset($urlParts['host'])) { + $urlParts['host'] = rtrim($urlParts['path'], "/"); + unset($urlParts['path']); + } + + if (!isset($urlParts['path'])) { + $urlParts['path'] = "/"; + } else { + $urlParts['path'] = rtrim($urlParts['path'], "/") . "/"; + } + + $_ENV['MAGENTO_BASE_URL'] = str_replace("///", "//", $this->build_url($urlParts)); + $this->config['url'] = str_replace("///", "//", $this->build_url($urlParts)); + } + + //Assign default Values to Selenium configs if they are defined + if ($this->config['protocol'] == '%SELENIUM_PROTOCOL%') { + $this->config['protocol'] = "http"; + } + if ($this->config['host'] == '%SELENIUM_HOST%') { + $this->config['host'] = "127.0.0.1"; + } + if ($this->config['port'] == '%SELENIUM_PORT%') { + $this->config['port'] = "4444"; + } + if ($this->config['path'] == '%SELENIUM_PATH%') { + $this->config['path'] = "/wd/hub"; + } + } + + /** + * Returns url from $parts given, used with parse_url output for convenience. + * This only exists because of deprecation of http_build_url, which does the exact same thing as the code below. + * @param array $parts + * @return string + */ + private function build_url(array $parts) { + $get = function ($key) use ($parts) { + return isset($parts[$key]) ? $parts[$key] : null; + }; + + $pass = $get('pass'); + $user = $get('user'); + $userinfo = $pass !== null ? "$user:$pass" : $user; + $port = $get('port'); + $scheme = $get('scheme'); + $query = $get('query'); + $fragment = $get('fragment'); + $authority = + ($userinfo !== null ? "$userinfo@" : '') . + $get('host') . + ($port ? ":$port" : ''); + + return + (strlen($scheme) ? "$scheme:" : '') . + (strlen($authority) ? "//$authority" : '') . + $get('path') . + (strlen($query) ? "?$query" : '') . + (strlen($fragment) ? "#$fragment" : ''); + } + /** * Returns URL of a host. * @@ -180,9 +271,16 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi * * @param int $timeout */ - public function waitForAjaxLoad($timeout = 15) + public function waitForAjaxLoad($timeout = null) { - $this->waitForJS('return !!window.jQuery && window.jQuery.active == 0;', $timeout); + $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; + + try { + $this->waitForJS('return !!window.jQuery && window.jQuery.active == 0;', $timeout); + } catch (\Exception $exceptione) { + $this->debug("js never executed, performing {$timeout} second wait."); + $this->wait($timeout); + } $this->wait(1); } @@ -191,11 +289,14 @@ public function waitForAjaxLoad($timeout = 15) * * @param int $timeout */ - public function waitForPageLoad($timeout = 15) + public function waitForPageLoad($timeout = null) { + $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; + $this->waitForJS('return document.readyState == "complete"', $timeout); $this->waitForAjaxLoad($timeout); $this->waitForLoadingMaskToDisappear(); + $this->closeAdminNotification(); } /** @@ -204,9 +305,13 @@ public function waitForPageLoad($timeout = 15) public function waitForLoadingMaskToDisappear() { foreach( self::$loadingMasksLocators as $maskLocator) { + // Get count of elements found for looping. + // Elements are NOT useful for interaction, as they cannot be fed to codeception actions. $loadingMaskElements = $this->_findElements($maskLocator); for ($i = 1; $i <= count($loadingMaskElements); $i++) { - $this->waitForElementNotVisible("{$maskLocator}[{$i}]", 30); + // Formatting and looping on i as we can't interact elements returned above + // eg. (//div[@data-role="spinner"])[1] + $this->waitForElementNotVisible("({$maskLocator})[{$i}]", 30); } } } @@ -255,7 +360,7 @@ public function parseFloat($floatString){ /** * @param int $category * @param string $locale - */ + */ public function mSetLocale(int $category, $locale) { if (self::$localeAll[$category] == $locale) { @@ -325,6 +430,26 @@ public function clearField($selector) $this->fillField($selector, ""); } + /** + * Assert that an element contains a given value for the specific attribute. + * + * @param string $selector + * @param string $attribute + * @param $value + */ + public function assertElementContainsAttribute($selector, $attribute, $value) + { + $attributes = $this->grabAttributeFrom($selector, $attribute); + + if (isset($value) && empty($value)) { + // If an "attribute" is blank, "", or null we need to be able to assert that it's present. + // When an "attribute" is blank or null it returns "true" so we assert that "true" is present. + $this->assertEquals($attributes, 'true'); + } else { + $this->assertContains($value, $attributes); + } + } + /** * Override for _failed method in Codeception method. Adds png and html attachments to allure report * following parent execution of test failure processing. diff --git a/src/Magento/FunctionalTestingFramework/ObjectManager/Config/SchemaLocator.php b/src/Magento/FunctionalTestingFramework/ObjectManager/Config/SchemaLocator.php index fd4f92b17..aabf0e8f6 100644 --- a/src/Magento/FunctionalTestingFramework/ObjectManager/Config/SchemaLocator.php +++ b/src/Magento/FunctionalTestingFramework/ObjectManager/Config/SchemaLocator.php @@ -22,7 +22,8 @@ class SchemaLocator implements SchemaLocatorInterface */ public function getSchema() { - return realpath(__DIR__ . '/../etc/') . DIRECTORY_SEPARATOR . 'config.xsd'; + return realpath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'etc' . DIRECTORY_SEPARATOR) + . DIRECTORY_SEPARATOR . 'config.xsd'; } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index 928911150..e2c280ac5 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -97,7 +97,7 @@ private function initPageObjects() $parsedObjs = $parser->getData(self::TYPE); if (!$parsedObjs) { - trigger_error("No " . self::TYPE . " objects defined", E_USER_NOTICE); + // No *Page.xml files found so give up return; } diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index a39db4c69..171eb5376 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -101,7 +101,7 @@ private function initSectionObjects() $parsedObjs = $parser->getData(self::TYPE); if (!$parsedObjs) { - trigger_error("No " . self::TYPE . " objects defined", E_USER_NOTICE); + // No *Section.xml files found so give up return; } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php index 043c267c2..ed7f690ed 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php @@ -22,7 +22,7 @@ class GroupClassGenerator const BEFORE_MUSTACHE_KEY = 'before'; const AFTER_MUSTACHE_KEY = 'after'; const ENTITY_NAME_TAG = 'entityName'; - const ENTITY_MERGE_KEY = 'mergeKey'; + const ENTITY_MERGE_KEY = 'stepKey'; const REQUIRED_ENTITY_KEY = 'requiredEntities'; const LAST_REQUIRED_ENTITY_TAG = 'last'; const MUSTACHE_VAR_TAG = 'var'; @@ -103,7 +103,7 @@ private function buildHookMustacheArray($hookObj) foreach ($hookObj->getActions() as $action) { /** @var ActionObject $action */ $entityArray = []; - $entityArray[self::ENTITY_MERGE_KEY] = $action->getMergeKey(); + $entityArray[self::ENTITY_MERGE_KEY] = $action->getStepKey(); $entityArray[self::ENTITY_NAME_TAG] = $action->getCustomActionAttributes()['entity'] ?? $action->getCustomActionAttributes()[TestGenerator::REQUIRED_ENTITY_REFERENCE]; @@ -123,7 +123,7 @@ private function buildHookMustacheArray($hookObj) /** * Function which takes any required entities under a 'createData' tag and transforms data into array to be consumed * by mustache template. - * ( + * ( * - - - - - - - - - - - - - - - - - diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index d55d6d0ee..87fd6caf8 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -21,7 +21,7 @@ class {{suiteName}} extends \Codeception\GroupObject private static $CURRENT_TEST_RUN = 0; {{#var}} - private ${{mergeKey}}; + private ${{stepKey}}; {{/var}} {{#before}} diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/partials/dataPersistence.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/partials/dataPersistence.mustache index 269204602..91602e594 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/partials/dataPersistence.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/partials/dataPersistence.mustache @@ -1,7 +1,7 @@ {{#createData}} ${{entityName}} = DataObjectHandler::getInstance()->getObject("{{entityName}}"); -$this->{{mergeKey}} = new DataPersistenceHandler(${{entityName}}, [{{#requiredEntities}}$this->{{entityName}}{{^last}}, {{/last}}{{/requiredEntities}}]); -$this->{{mergeKey}}->createEntity(); +$this->{{stepKey}} = new DataPersistenceHandler(${{entityName}}, [{{#requiredEntities}}$this->{{entityName}}{{^last}}, {{/last}}{{/requiredEntities}}]); +$this->{{stepKey}}->createEntity(); {{/createData}} {{#deleteData}} $this->{{entityName}}->deleteEntity(); diff --git a/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php b/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php index b00aaa6ed..254cdcc69 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php +++ b/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php @@ -14,6 +14,9 @@ */ class Flat implements ConverterInterface { + const REMOVE_ACTION = 'remove'; + const REMOVE_KEY_ATTRIBUTE = 'keyForRemoval'; + /** * Array node configuration. * @@ -70,10 +73,9 @@ public function convertXml(\DOMNode $source, $basePath = '') $value = []; /** @var \DOMNode $node */ foreach ($source->childNodes as $node) { - if ($node->nodeType == XML_ELEMENT_NODE && $node->getAttribute('remove') != 'true') { + if ($node->nodeType == XML_ELEMENT_NODE) { $nodeName = $node->nodeName; $nodePath = $basePath . '/' . $nodeName; - $arrayKeyAttribute = $this->arrayNodeConfig->getAssocArrayKeyAttribute($nodePath); $isNumericArrayNode = $this->arrayNodeConfig->isNumericArray($nodePath); $isArrayNode = $isNumericArrayNode || $arrayKeyAttribute; @@ -84,6 +86,11 @@ public function convertXml(\DOMNode $source, $basePath = '') ); } + if ($nodeName == self::REMOVE_ACTION) { + unset($value[$node->getAttribute(self::REMOVE_KEY_ATTRIBUTE)]); + continue; + } + $nodeData = $this->convertXml($node, $nodePath); if ($isArrayNode) { if ($isNumericArrayNode) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index 40feb93de..19f666bc5 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -133,8 +133,8 @@ private function getResolvedActionsWithArgs($arguments, $actionReferenceKey) // we append the action reference key to any linked action and the action's merge key as the user might // use this action group multiple times in the same test. - $resolvedActions[$action->getMergeKey() . $actionReferenceKey] = new ActionObject( - $action->getMergeKey() . $actionReferenceKey, + $resolvedActions[$action->getStepKey() . $actionReferenceKey] = new ActionObject( + $action->getStepKey() . $actionReferenceKey, $action->getType(), array_merge($action->getCustomActionAttributes(), $newActionAttributes), $action->getLinkedAction() == null ? null : $action->getLinkedAction() . $actionReferenceKey, @@ -217,7 +217,8 @@ private function replaceAttributeArgumentInVariable( ); } - return str_replace($variableName, $arguments[$variableName], $attributeValue); + //replace argument ONLY when there is no letters attached before after (ex. category.name vs categoryTreeButton) + return preg_replace("/(?mergeKey = $mergeKey; + $this->stepKey = $stepKey; $this->type = $type; $this->actionAttributes = $actionAttributes; $this->linkedAction = $linkedAction; @@ -104,13 +104,13 @@ public function __construct( } /** - * This function returns the string property mergeKey. + * This function returns the string property stepKey. * * @return string */ - public function getMergeKey() + public function getStepKey() { - return $this->mergeKey; + return $this->stepKey; } /** @@ -125,7 +125,7 @@ public function getType() /** * This function returns an array of action attributes mapped by key. For example - * the tag has 3 attributes, + * the tag has 3 attributes, * only 2 of which are specific to the 'seeNumberOfElements' tag. As a result this function would * return the array would return [selector => value1, expected => value2] * The returned array is also the merged result of the resolved and normal actions, giving @@ -169,6 +169,17 @@ public function getTimeout() return $this->timeout; } + /** + * Set the timeout value. + * + * @param int $timeout + * @return void + */ + public function setTimeout($timeout) + { + $this->timeout = $timeout; + } + /** * Populate the resolved custom attributes array with lookup values for the following attributes: * selector @@ -332,7 +343,7 @@ private function findAndReplaceReferences($objectHandler, $inputString) // If no Selector is defined, assume element has LocatorFunction $replacement = $obj->getElement($objField)->getSelector() ?: $obj->getElement($objField)->getLocatorFunction(); - $this->timeout = $obj->getElement($objField)->getTimeout(); + $this->setTimeout($obj->getElement($objField)->getTimeout()); break; case (get_class($obj) == EntityDataObject::class): list(,$objField) = $this->stripAndSplitReference($match); diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php index e1035a867..8af5e3af0 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php @@ -144,10 +144,10 @@ private function insertWaits() if ($step->getTimeout()) { $waitStepAttributes = [self::WAIT_ATTR => $step->getTimeout()]; $waitStep = new ActionObject( - $step->getMergeKey() . self::WAIT_ACTION_SUFFIX, + $step->getStepKey() . self::WAIT_ACTION_SUFFIX, self::WAIT_ACTION_NAME, $waitStepAttributes, - $step->getMergeKey(), + $step->getStepKey(), self::DEFAULT_WAIT_ORDER ); $this->insertStep($waitStep); @@ -167,9 +167,9 @@ private function sortActions($parsedSteps) foreach ($parsedSteps as $parsedStep) { $parsedStep->resolveReferences(); if ($parsedStep->getLinkedAction()) { - $this->stepsToMerge[$parsedStep->getMergeKey()] = $parsedStep; + $this->stepsToMerge[$parsedStep->getStepKey()] = $parsedStep; } else { - $this->orderedSteps[$parsedStep->getMergeKey()] = $parsedStep; + $this->orderedSteps[$parsedStep->getStepKey()] = $parsedStep; } } } @@ -192,7 +192,7 @@ private function mergeAction($stepToMerge) self::STEP_MISSING_ERROR_MSG, $this->type, $this->name, - $stepToMerge->getMergeKey(), + $stepToMerge->getStepKey(), $linkedStep )); } elseif (!array_key_exists($linkedStep, $this->orderedSteps)) { @@ -216,6 +216,6 @@ private function insertStep($stepToMerge) ) + $stepToMerge->getOrderOffset(); $previous_items = array_slice($this->orderedSteps, 0, $position, true); $next_items = array_slice($this->orderedSteps, $position, null, true); - $this->orderedSteps = $previous_items + [$stepToMerge->getMergeKey() => $stepToMerge] + $next_items; + $this->orderedSteps = $previous_items + [$stepToMerge->getStepKey() => $stepToMerge] + $next_items; } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php index b137102e4..812955df7 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php @@ -16,7 +16,7 @@ class ActionObjectExtractor extends BaseCestObjectExtractor { const TEST_ACTION_BEFORE = 'before'; const TEST_ACTION_AFTER = 'after'; - const TEST_STEP_MERGE_KEY = 'mergeKey'; + const TEST_STEP_MERGE_KEY = 'stepKey'; const ACTION_GROUP_TAG = 'actionGroup'; const ACTION_GROUP_REF = 'ref'; const ACTION_GROUP_ARGUMENTS = 'arguments'; @@ -44,7 +44,7 @@ public function extractActions($testActions) $actions = []; foreach ($testActions as $actionName => $actionData) { - $mergeKey = $actionData[self::TEST_STEP_MERGE_KEY]; + $stepKey = $actionData[self::TEST_STEP_MERGE_KEY]; if ($actionData[self::NODE_NAME] === TestEntityExtractor::TEST_STEP_ENTITY_CREATION) { $actionData = $this->stripDataFields($actionData); } @@ -79,7 +79,7 @@ public function extractActions($testActions) }*/ $actions[] = new ActionObject( - $mergeKey, + $stepKey, $actionData[self::NODE_NAME], $actionAttributes, $linkedAction, diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestEntityExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestEntityExtractor.php index d6ce1b7bf..cc1ae54fe 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestEntityExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestEntityExtractor.php @@ -28,7 +28,7 @@ public function __construct() /** * Extracts custom entity or data definitions from test actions. - * Returns array of entity data objects indexed by mergeKey, and an array of key-value pairs. + * Returns array of entity data objects indexed by stepKey, and an array of key-value pairs. * @param array $testActions * @return array $entityData */ diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/sampleActionGroup.xml b/src/Magento/FunctionalTestingFramework/Test/etc/sampleActionGroup.xml deleted file mode 100644 index e0be8ca20..000000000 --- a/src/Magento/FunctionalTestingFramework/Test/etc/sampleActionGroup.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/sampleCest.xml b/src/Magento/FunctionalTestingFramework/Test/etc/sampleCest.xml deleted file mode 100644 index c6966af5a..000000000 --- a/src/Magento/FunctionalTestingFramework/Test/etc/sampleCest.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd index 1bb521a3e..2acb39a13 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd @@ -90,11 +90,13 @@ + + @@ -251,19 +253,26 @@ - - + + + + + + + + + + - - + @@ -274,8 +283,7 @@ - - + @@ -286,8 +294,7 @@ - - + @@ -298,8 +305,7 @@ - - + @@ -308,11 +314,23 @@ - + - - + + + + + + + + + + + + + + @@ -321,11 +339,10 @@ - + - - + @@ -334,8 +351,7 @@ - - + @@ -344,9 +360,8 @@ - - - + + @@ -355,9 +370,8 @@ - - - + + @@ -370,8 +384,7 @@ - - + @@ -384,8 +397,7 @@ - - + @@ -398,8 +410,7 @@ - - + @@ -408,8 +419,7 @@ - - + @@ -418,8 +428,7 @@ - - + @@ -428,9 +437,8 @@ - - - + + @@ -439,11 +447,10 @@ - - - - - + + + + @@ -454,8 +461,7 @@ - - + @@ -464,7 +470,6 @@ - @@ -475,9 +480,8 @@ - + - @@ -485,9 +489,8 @@ - - - + + @@ -499,9 +502,8 @@ - + - @@ -513,8 +515,7 @@ - - + @@ -523,9 +524,8 @@ - - - + + @@ -537,8 +537,7 @@ - - + @@ -549,8 +548,7 @@ - - + @@ -561,8 +559,7 @@ - - + @@ -571,10 +568,9 @@ - + - - + @@ -583,11 +579,9 @@ - + - - - + @@ -598,8 +592,7 @@ - - + @@ -612,8 +605,7 @@ - - + @@ -622,10 +614,9 @@ - + - - + @@ -636,8 +627,7 @@ - - + @@ -646,9 +636,8 @@ - - - + + @@ -659,8 +648,7 @@ - - + @@ -669,8 +657,7 @@ - - + @@ -682,8 +669,7 @@ - - + @@ -692,11 +678,10 @@ - + - - + @@ -705,9 +690,8 @@ - - - + + @@ -716,10 +700,9 @@ - - - - + + + @@ -728,9 +711,8 @@ - - - + + @@ -739,9 +721,8 @@ - - - + + @@ -754,8 +735,7 @@ - - + @@ -767,8 +747,7 @@ - - + @@ -777,12 +756,11 @@ - + - + - - + @@ -793,10 +771,9 @@ - + - - + @@ -806,10 +783,9 @@ - + - - + @@ -818,12 +794,11 @@ - + - + - - + @@ -832,9 +807,8 @@ - - - + + @@ -843,10 +817,9 @@ - - - - + + + @@ -857,9 +830,8 @@ - - - + + @@ -871,8 +843,7 @@ - - + @@ -883,8 +854,7 @@ - - + @@ -895,8 +865,7 @@ - - + @@ -905,8 +874,7 @@ - - + @@ -916,10 +884,9 @@ - + - - + @@ -928,8 +895,7 @@ - - + @@ -938,8 +904,7 @@ - - + @@ -948,8 +913,7 @@ - - + @@ -962,8 +926,7 @@ - - + @@ -972,8 +935,7 @@ - - + @@ -984,8 +946,7 @@ - - + @@ -994,8 +955,7 @@ - - + @@ -1004,10 +964,9 @@ - - - - + + + @@ -1016,12 +975,11 @@ - + - - + @@ -1030,8 +988,7 @@ - - + @@ -1043,8 +1000,7 @@ - - + @@ -1053,10 +1009,9 @@ - - - - + + + @@ -1067,8 +1022,7 @@ - - + @@ -1081,8 +1035,7 @@ - - + @@ -1091,8 +1044,7 @@ - - + @@ -1101,12 +1053,10 @@ - - - + + - - + @@ -1119,8 +1069,7 @@ - - + @@ -1129,9 +1078,8 @@ - - - + + @@ -1143,8 +1091,7 @@ - - + @@ -1155,8 +1102,7 @@ - - + @@ -1167,8 +1113,7 @@ - - + @@ -1180,8 +1125,7 @@ - - + @@ -1190,10 +1134,9 @@ - + - - + @@ -1204,8 +1147,7 @@ - - + @@ -1218,8 +1160,7 @@ - - + @@ -1228,10 +1169,9 @@ - - - - + + + @@ -1240,9 +1180,8 @@ - - - + + @@ -1253,8 +1192,7 @@ - - + @@ -1263,9 +1201,8 @@ - - - + + @@ -1276,8 +1213,7 @@ - - + @@ -1289,8 +1225,7 @@ - - + @@ -1299,12 +1234,11 @@ - + - - + @@ -1313,11 +1247,10 @@ - + - - + @@ -1326,12 +1259,11 @@ - + - - + @@ -1340,11 +1272,10 @@ - + - - - + + @@ -1353,11 +1284,10 @@ - - + + - - + @@ -1369,8 +1299,7 @@ - - + @@ -1381,8 +1310,7 @@ - - + @@ -1393,8 +1321,7 @@ - - + @@ -1405,8 +1332,7 @@ - - + @@ -1417,8 +1343,7 @@ - - + @@ -1427,9 +1352,8 @@ - - - + + @@ -1438,12 +1362,11 @@ - + - - + @@ -1453,8 +1376,7 @@ - - + @@ -1464,8 +1386,7 @@ - - + @@ -1474,11 +1395,10 @@ - - + + - - + @@ -1487,10 +1407,9 @@ - + - - + @@ -1499,10 +1418,9 @@ - + - - + @@ -1511,10 +1429,9 @@ - + - - + @@ -1523,10 +1440,9 @@ - + - - + @@ -1535,8 +1451,7 @@ - - + @@ -1546,8 +1461,7 @@ - - + @@ -1560,8 +1474,7 @@ - - + @@ -1570,13 +1483,12 @@ - - - - + + + + - - + @@ -1585,13 +1497,12 @@ - - - - + + + + - - + @@ -1600,14 +1511,13 @@ - - - - + + + + - - + @@ -1616,13 +1526,12 @@ - - - - + + + + - - + @@ -1631,13 +1540,12 @@ - - - - + + + + - - + @@ -1646,11 +1554,10 @@ - - + + - - + @@ -1659,14 +1566,13 @@ - - - - + + + + - - + @@ -1675,11 +1581,10 @@ - - + + - - + @@ -1688,11 +1593,10 @@ - - + + - - + @@ -1701,11 +1605,10 @@ - - + + - - + @@ -1714,13 +1617,12 @@ - - - - + + + + - - + @@ -1729,13 +1631,12 @@ - - - - + + + + - - + @@ -1744,13 +1645,12 @@ - - - - + + + + - - + @@ -1759,13 +1659,12 @@ - - - - + + + + - - + @@ -1774,13 +1673,12 @@ - - - - + + + + - - + @@ -1789,11 +1687,10 @@ - - + + - - + @@ -1802,13 +1699,12 @@ - - - - + + + + - - + @@ -1817,13 +1713,12 @@ - - - - + + + + - - + @@ -1832,13 +1727,12 @@ - - - - + + + + - - + @@ -1847,13 +1741,12 @@ - - - - + + + + - - + @@ -1862,11 +1755,10 @@ - - + + - - + @@ -1875,14 +1767,13 @@ - - - - + + + + - - + @@ -1891,13 +1782,12 @@ - - - - + + + + - - + @@ -1906,11 +1796,10 @@ - - + + - - + @@ -1919,13 +1808,12 @@ - - - - + + + + - - + @@ -1934,13 +1822,12 @@ - - - - + + + + - - + @@ -1949,11 +1836,10 @@ - - + + - - + @@ -1962,13 +1848,12 @@ - - - - + + + + - - + @@ -1977,13 +1862,12 @@ - - - - + + + + - - + @@ -1992,13 +1876,12 @@ - - - - + + + + - - + @@ -2007,13 +1890,12 @@ - - - - + + + + - - + @@ -2022,11 +1904,10 @@ - - + + - - + @@ -2035,12 +1916,11 @@ - - - - - - + + + + + @@ -2049,9 +1929,8 @@ - - - + + diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 19c541f10..131e449a2 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -74,6 +74,15 @@ class ModuleResolver */ protected $sequenceSorter; + /** + * List of module names that will be ignored. + * + * @var array + */ + protected $moduleBlacklist = [ + 'SampleTests', + ]; + /** * Get ModuleResolver instance. * @@ -157,7 +166,7 @@ protected function getModuleWhitelist() public function getModulesPath() { if (isset($this->enabledModulePaths)) { - return $this->enabledModulePaths; + return $this->removeBlacklistModules($this->enabledModulePaths); } $enabledModules = $this->getEnabledModules(); @@ -165,7 +174,7 @@ public function getModulesPath() $allModulePaths = glob($modulePath . '*/*'); if (empty($enabledModules)) { $this->enabledModulePaths = $allModulePaths; - return $this->enabledModulePaths; + return $this->removeBlacklistModules($this->enabledModulePaths); } $enabledModules = array_merge($enabledModules, $this->getModuleWhitelist()); @@ -183,7 +192,7 @@ public function getModulesPath() } $this->enabledModulePaths = $allModulePaths; - return $this->enabledModulePaths; + return $this->removeBlacklistModules($this->enabledModulePaths); } /** @@ -193,8 +202,8 @@ public function getModulesPath() */ protected function getAdminToken() { - $login = $_ENV['MAGENTO_ADMIN_USERNAME']; - $password = $_ENV['MAGENTO_ADMIN_PASSWORD']; + $login = $_ENV['MAGENTO_ADMIN_USERNAME'] ?? null; + $password = $_ENV['MAGENTO_ADMIN_PASSWORD'] ?? null; if (!$login || !$password || !isset($_ENV['MAGENTO_BASE_URL'])) { return false; } @@ -231,4 +240,30 @@ public function sortFilesByModuleSequence(array $files) { return $this->sequenceSorter->sort($files); } + + /** + * Remove blacklist modules from input module paths. + * + * @param array &$modulePaths + * @return array + */ + protected function removeBlacklistModules(&$modulePaths) + { + foreach ($modulePaths as $index => $modulePath) { + if (in_array(basename($modulePath), $this->getModuleBlacklist())) { + unset($modulePaths[$index]); + } + } + return $modulePaths; + } + + /** + * Getter for moduleBlacklist. + * + * @return array + */ + protected function getModuleBlacklist() + { + return $this->moduleBlacklist; + } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 94e1117ac..4a2b2c829 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -344,7 +344,9 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) foreach ($stepsObject as $steps) { $actor = "I"; $actionName = $steps->getType(); + $stepKey = $steps->getStepKey(); $customActionAttributes = $steps->getCustomActionAttributes(); + $attribute = null; $selector = null; $selector1 = null; $selector2 = null; @@ -375,10 +377,17 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $assertIsStrict = null; $assertDelta = null; + // Validate action attributes and print notice messages on violation. + $this->validateXmlAttributesMutuallyExclusive($stepKey, $actionName, $customActionAttributes); + if (isset($customActionAttributes['returnVariable'])) { $returnVariable = $customActionAttributes['returnVariable']; } + if (isset($customActionAttributes['attribute'])) { + $attribute = $customActionAttributes['attribute']; + } + if (isset($customActionAttributes['variable'])) { $input = $this->addDollarSign($customActionAttributes['variable']); } elseif (isset($customActionAttributes['userInput']) && isset($customActionAttributes['url'])) { @@ -388,6 +397,8 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $input = $this->addUniquenessFunctionCall($customActionAttributes['userInput']); } elseif (isset($customActionAttributes['url'])) { $input = $this->addUniquenessFunctionCall($customActionAttributes['url']); + } elseif (isset($customActionAttributes['expectedValue'])) { + $input = $this->addUniquenessFunctionCall($customActionAttributes['expectedValue']); } if (isset($customActionAttributes['expected'])) { $assertExpected = $this->resolveValueByType( @@ -507,12 +518,11 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) switch ($actionName) { case "createData": $entity = $customActionAttributes['entity']; - $key = $steps->getMergeKey(); //Add an informative statement to help the user debug test runs $testSteps .= sprintf( - "\t\t$%s->amGoingTo(\"create entity that has the mergeKey: %s\");\n", + "\t\t$%s->amGoingTo(\"create entity that has the stepKey: %s\");\n", $actor, - $key + $stepKey ); //Get Entity from Static data. $testSteps .= sprintf( @@ -544,17 +554,17 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) } if ($hookObject) { - $createEntityFunctionCall = sprintf("\t\t\$this->%s->createEntity(", $key); + $createEntityFunctionCall = sprintf("\t\t\$this->%s->createEntity(", $stepKey); $dataPersistenceHandlerFunctionCall = sprintf( "\t\t\$this->%s = new DataPersistenceHandler($%s", - $key, + $stepKey, $entity ); } else { - $createEntityFunctionCall = sprintf("\t\t\$%s->createEntity(", $key); + $createEntityFunctionCall = sprintf("\t\t\$%s->createEntity(", $stepKey); $dataPersistenceHandlerFunctionCall = sprintf( "\t\t$%s = new DataPersistenceHandler($%s", - $key, + $stepKey, $entity ); } @@ -649,12 +659,11 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) break; case "getData": $entity = $customActionAttributes['entity']; - $key = $steps->getMergeKey(); //Add an informative statement to help the user debug test runs $testSteps .= sprintf( - "\t\t$%s->amGoingTo(\"get entity that has the mergeKey: %s\");\n", + "\t\t$%s->amGoingTo(\"get entity that has the stepKey: %s\");\n", $actor, - $key + $stepKey ); //Get Entity from Static data. $testSteps .= sprintf( @@ -686,17 +695,17 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) } if ($hookObject) { - $getEntityFunctionCall = sprintf("\t\t\$this->%s->getEntity(", $key); + $getEntityFunctionCall = sprintf("\t\t\$this->%s->getEntity(", $stepKey); $dataPersistenceHandlerFunctionCall = sprintf( "\t\t\$this->%s = new DataPersistenceHandler($%s", - $key, + $stepKey, $entity ); } else { - $getEntityFunctionCall = sprintf("\t\t\$%s->getEntity(", $key); + $getEntityFunctionCall = sprintf("\t\t\$%s->getEntity(", $stepKey); $dataPersistenceHandlerFunctionCall = sprintf( "\t\t$%s = new DataPersistenceHandler($%s", - $key, + $stepKey, $entity ); } @@ -968,6 +977,20 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $assertDelta ); break; + case "assertElementContainsAttribute": + // If a blank string or null is passed in we need to pass a blank string to the function. + if (empty($input)) { + $input = '""'; + } + + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $selector, + $this->wrapWithDoubleQuotes($attribute), + $input + ); + break; case "assertEmpty": case "assertFalse": case "assertFileExists": @@ -1080,7 +1103,7 @@ private function replaceMatchesIntoArg($matches, &$outputArg, $delimiter) if (count($variable) != 2) { throw new \Exception( "Invalid Persisted Entity Reference: {$match}. - Test persisted entity references must follow {$delimiter}entityMergeKey.field{$delimiter} format." + Test persisted entity references must follow {$delimiter}entityStepKey.field{$delimiter} format." ); } if ($delimiter == "$") { @@ -1185,13 +1208,13 @@ private function generateHooksPhp($hookObjects) || ($step->getType() == "getData") ) { $hooks .= "\t/**\n"; - $hooks .= sprintf("\t * @var DataPersistenceHandler $%s;\n", $step->getMergeKey()); + $hooks .= sprintf("\t * @var DataPersistenceHandler $%s;\n", $step->getStepKey()); $hooks .= "\t */\n"; - $hooks .= sprintf("\tprotected $%s;\n\n", $step->getMergeKey()); + $hooks .= sprintf("\tprotected $%s;\n\n", $step->getStepKey()); $createData = true; } elseif ($step->getType() == "entity") { $hooks .= "\t/**\n"; - $hooks .= sprintf("\t * @var EntityDataObject $%s;\n", $step->getMergeKey()); + $hooks .= sprintf("\t * @var EntityDataObject $%s;\n", $step->getStepKey()); $hooks .= "\t */\n"; $hooks .= sprintf("\tprotected $%s;\n\n", $step->getCustomActionAttributes()['name']); } @@ -1515,4 +1538,81 @@ private function stripQuotes($inStr) $unquoted = preg_replace('/^(\'(.*)\'|"(.*)")$/', '$2$3', $inStr); return $unquoted; } + + /** + * Validate action attributes are either not set at all or only one is set for a given rule. + * + * @param string $key + * @param string $tagName + * @param array $attributes + * @return void + */ + private function validateXmlAttributesMutuallyExclusive($key, $tagName, $attributes) + { + $rules = [ + [ 'attributes' => [ + 'selector', + 'selectorArray', + ] + ], + [ + 'attributes' => [ + 'url', + 'userInput', + 'variable', + ], + 'excludes' => [ + 'dontSeeLink', + 'seeLink', + ], + ], + [ + 'attributes' => [ + 'userInput', + 'parameterArray', + 'variable' + ], + 'excludes' => [ + 'dontSeeCookie', + 'grabCookie', + 'resetCookie', + 'seeCookie', + 'setCookie', + ], + ], + ]; + foreach ($rules as $rule) { + if (isset($rule['excludes']) && in_array($tagName, $rule['excludes'])) { + continue; + } + $count = 0; + foreach ($rule['attributes'] as $attribute) { + if (isset($attributes[$attribute])) { + $count++; + } + } + if ($count > 1) { + $this->printRuleErrorToConsole($key, $tagName, $rule['attributes']); + } + } + } + + /** + * Print rule violation message to console. + * + * @param string $key + * @param string $tagName + * @param array $attributes + * @return void + */ + private function printRuleErrorToConsole($key, $tagName, $attributes) + { + if (empty($tagName) || empty($attributes)) { + return; + } + $message = 'On step with stepKey "' . $key . '", only one of the attributes: "'; + $message .= implode('", "', $attributes); + $message .= '" can be use for action "' . $tagName . "\".\n"; + print $message; + } }